Update openpgp-api-library

This commit is contained in:
Dominik Schürmann 2015-01-28 15:11:08 +01:00
parent d112344780
commit bc2fe2dbfe
30 changed files with 502 additions and 107 deletions

View File

@ -6,7 +6,7 @@
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="17" />
android:targetSdkVersion="19" />
<application/>

View File

@ -0,0 +1,21 @@
# OpenPGP API library
The OpenPGP API provides methods to execute OpenPGP operations, such as sign, encrypt, decrypt, verify, and more without user interaction from background threads. This is done by connecting your client application to a remote service provided by [OpenKeychain](http://www.openkeychain.org) or other OpenPGP providers.
For usage instructions, please consult our Wiki page about the [OpenPGP API](https://github.com/open-keychain/open-keychain/wiki/OpenPGP-API).
License
=======
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -14,7 +14,7 @@ apply plugin: 'com.android.library'
android {
compileSdkVersion 21
buildToolsVersion '21.1.2'
// NOTE: We are using the old folder structure to also support Eclipse
sourceSets {
main {
@ -27,7 +27,7 @@ android {
assets.srcDirs = ['assets']
}
}
// Do not abort build if lint finds errors
lintOptions {
abortOnError false

View File

@ -0,0 +1,15 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-19
android.library=true

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Žádný</string>
<string name="openpgp_install_openkeychain_via">Instalovat OpenKeychain pomocí %s</string>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Keine Auswahl</string>
<string name="openpgp_install_openkeychain_via">Installiere OpenKeychain mit %s</string>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Ninguno</string>
<string name="openpgp_install_openkeychain_via">Instalar OpenKeychain mediante %s</string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Aucun</string>
<string name="openpgp_install_openkeychain_via">Installer OpenKeychain par %s</string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Nessuno</string>
<string name="openpgp_install_openkeychain_via">Installa OpenKeychain via %s</string>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">無し</string>
<string name="openpgp_install_openkeychain_via">%s 経由でOpenKeychainをインストール</string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Нет</string>
<string name="openpgp_install_openkeychain_via">Установить OpenKeychain через %s</string>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Brez</string>
<string name="openpgp_install_openkeychain_via">Namesti OpenKeychain prek %s</string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -0,0 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="openpgp_list_preference_none">Жоден</string>
<string name="openpgp_install_openkeychain_via">Встановити OpenKeychain через %s</string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources/>

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -0,0 +1,132 @@
/*
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.openpgp;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Parcelable versioning has been copied from Dashclock Widget
* https://code.google.com/p/dashclock/source/browse/api/src/main/java/com/google/android/apps/dashclock/api/ExtensionData.java
*/
public class OpenPgpMetadata implements Parcelable {
/**
* Since there might be a case where new versions of the client using the library getting
* old versions of the protocol (and thus old versions of this class), we need a versioning
* system for the parcels sent between the clients and the providers.
*/
public static final int PARCELABLE_VERSION = 1;
String filename;
String mimeType;
long modificationTime;
long originalSize;
public String getFilename() {
return filename;
}
public String getMimeType() {
return mimeType;
}
public long getModificationTime() {
return modificationTime;
}
public long getOriginalSize() {
return originalSize;
}
public OpenPgpMetadata() {
}
public OpenPgpMetadata(String filename, String mimeType, long modificationTime,
long originalSize) {
this.filename = filename;
this.mimeType = mimeType;
this.modificationTime = modificationTime;
this.originalSize = originalSize;
}
public OpenPgpMetadata(OpenPgpMetadata b) {
this.filename = b.filename;
this.mimeType = b.mimeType;
this.modificationTime = b.modificationTime;
this.originalSize = b.originalSize;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
/**
* NOTE: When adding fields in the process of updating this API, make sure to bump
* {@link #PARCELABLE_VERSION}.
*/
dest.writeInt(PARCELABLE_VERSION);
// Inject a placeholder that will store the parcel size from this point on
// (not including the size itself).
int sizePosition = dest.dataPosition();
dest.writeInt(0);
int startPosition = dest.dataPosition();
// version 1
dest.writeString(filename);
dest.writeString(mimeType);
dest.writeLong(modificationTime);
dest.writeLong(originalSize);
// Go back and write the size
int parcelableSize = dest.dataPosition() - startPosition;
dest.setDataPosition(sizePosition);
dest.writeInt(parcelableSize);
dest.setDataPosition(startPosition + parcelableSize);
}
public static final Creator<OpenPgpMetadata> CREATOR = new Creator<OpenPgpMetadata>() {
public OpenPgpMetadata createFromParcel(final Parcel source) {
int parcelableVersion = source.readInt();
int parcelableSize = source.readInt();
int startPosition = source.dataPosition();
OpenPgpMetadata vr = new OpenPgpMetadata();
vr.filename = source.readString();
vr.mimeType = source.readString();
vr.modificationTime = source.readLong();
vr.originalSize = source.readLong();
// skip over all fields added in future versions of this parcel
source.setDataPosition(startPosition + parcelableSize);
return vr;
}
public OpenPgpMetadata[] newArray(final int size) {
return new OpenPgpMetadata[size];
}
};
@Override
public String toString() {
String out = "\nfilename: " + filename;
out += "\nmimeType: " + mimeType;
out += "\nmodificationTime: " + modificationTime;
out += "\noriginalSize: " + originalSize;
return out;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,6 +19,11 @@ package org.openintents.openpgp;
import android.os.Parcel;
import android.os.Parcelable;
import org.openintents.openpgp.util.OpenPgpUtils;
import java.util.ArrayList;
import java.util.Locale;
/**
* Parcelable versioning has been copied from Dashclock Widget
* https://code.google.com/p/dashclock/source/browse/api/src/main/java/com/google/android/apps/dashclock/api/ExtensionData.java
@ -29,20 +34,25 @@ public class OpenPgpSignatureResult implements Parcelable {
* old versions of the protocol (and thus old versions of this class), we need a versioning
* system for the parcels sent between the clients and the providers.
*/
public static final int PARCELABLE_VERSION = 1;
public static final int PARCELABLE_VERSION = 2;
// generic error on signature verification
public static final int SIGNATURE_ERROR = 0;
// successfully verified signature, with certified public key
// successfully verified signature, with certified key
public static final int SIGNATURE_SUCCESS_CERTIFIED = 1;
// no public key was found for this signature verification
public static final int SIGNATURE_UNKNOWN_PUB_KEY = 2;
// successfully verified signature, but with uncertified public key
// no key was found for this signature verification
public static final int SIGNATURE_KEY_MISSING = 2;
// successfully verified signature, but with uncertified key
public static final int SIGNATURE_SUCCESS_UNCERTIFIED = 3;
// key has been revoked
public static final int SIGNATURE_KEY_REVOKED = 4;
// key is expired
public static final int SIGNATURE_KEY_EXPIRED = 5;
int status;
boolean signatureOnly;
String userId;
String primaryUserId;
ArrayList<String> userIds;
long keyId;
public int getStatus() {
@ -61,12 +71,20 @@ public class OpenPgpSignatureResult implements Parcelable {
this.signatureOnly = signatureOnly;
}
public String getUserId() {
return userId;
public String getPrimaryUserId() {
return primaryUserId;
}
public void setUserId(String userId) {
this.userId = userId;
public void setPrimaryUserId(String primaryUserId) {
this.primaryUserId = primaryUserId;
}
public ArrayList<String> getUserIds() {
return userIds;
}
public void setUserIds(ArrayList<String> userIds) {
this.userIds = userIds;
}
public long getKeyId() {
@ -82,18 +100,20 @@ public class OpenPgpSignatureResult implements Parcelable {
}
public OpenPgpSignatureResult(int signatureStatus, String signatureUserId,
boolean signatureOnly, long keyId) {
boolean signatureOnly, long keyId, ArrayList<String> userIds) {
this.status = signatureStatus;
this.signatureOnly = signatureOnly;
this.userId = signatureUserId;
this.primaryUserId = signatureUserId;
this.keyId = keyId;
this.userIds = userIds;
}
public OpenPgpSignatureResult(OpenPgpSignatureResult b) {
this.status = b.status;
this.userId = b.userId;
this.primaryUserId = b.primaryUserId;
this.signatureOnly = b.signatureOnly;
this.keyId = b.keyId;
this.userIds = b.userIds;
}
public int describeContents() {
@ -114,8 +134,10 @@ public class OpenPgpSignatureResult implements Parcelable {
// version 1
dest.writeInt(status);
dest.writeByte((byte) (signatureOnly ? 1 : 0));
dest.writeString(userId);
dest.writeString(primaryUserId);
dest.writeLong(keyId);
// version 2
dest.writeStringList(userIds);
// Go back and write the size
int parcelableSize = dest.dataPosition() - startPosition;
dest.setDataPosition(sizePosition);
@ -132,8 +154,10 @@ public class OpenPgpSignatureResult implements Parcelable {
OpenPgpSignatureResult vr = new OpenPgpSignatureResult();
vr.status = source.readInt();
vr.signatureOnly = source.readByte() == 1;
vr.userId = source.readString();
vr.primaryUserId = source.readString();
vr.keyId = source.readLong();
vr.userIds = new ArrayList<String>();
source.readStringList(vr.userIds);
// skip over all fields added in future versions of this parcel
source.setDataPosition(startPosition + parcelableSize);
@ -148,11 +172,11 @@ public class OpenPgpSignatureResult implements Parcelable {
@Override
public String toString() {
String out = new String();
out += "\nstatus: " + status;
out += "\nuserId: " + userId;
String out = "\nstatus: " + status;
out += "\nprimaryUserId: " + primaryUserId;
out += "\nuserIds: " + userIds;
out += "\nsignatureOnly: " + signatureOnly;
out += "\nkeyId: " + keyId;
out += "\nkeyId: " + OpenPgpUtils.convertKeyIdToHex(keyId);
return out;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,10 +23,10 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import org.openintents.openpgp.IOpenPgpService;
import org.openintents.openpgp.OpenPgpError;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -34,9 +34,31 @@ public class OpenPgpApi {
public static final String TAG = "OpenPgp API";
public static final int API_VERSION = 3;
public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService";
/**
* Version history
* ---------------
* <p/>
* 3:
* - First public stable version
* <p/>
* 4:
* - No changes to existing methods -> backward compatible
* - Introduction of ACTION_DECRYPT_METADATA, RESULT_METADATA, EXTRA_ORIGINAL_FILENAME, and OpenPgpMetadata parcel
* - Introduction of internal NFC extras: EXTRA_NFC_SIGNED_HASH, EXTRA_NFC_SIG_CREATION_TIMESTAMP
* 5:
* - OpenPgpSignatureResult: new consts SIGNATURE_KEY_REVOKED and SIGNATURE_KEY_EXPIRED
* - OpenPgpSignatureResult: ArrayList<String> userIds
* 6:
* - Deprecate ACTION_SIGN
* - Introduce ACTION_CLEARTEXT_SIGN and ACTION_DETACHED_SIGN
* - New extra for ACTION_DETACHED_SIGN: EXTRA_DETACHED_SIGNATURE
* - New result for ACTION_DECRYPT_VERIFY: RESULT_DETACHED_SIGNATURE
* - New result for ACTION_DECRYPT_VERIFY: RESULT_CHARSET
*/
public static final int API_VERSION = 6;
/**
* General extras
* --------------
@ -51,75 +73,118 @@ public class OpenPgpApi {
*/
/**
* Sign only
*
* DEPRECATED
* Same as ACTION_CLEARTEXT_SIGN
* <p/>
* optional extras:
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput)
* boolean EXTRA_REQUEST_ASCII_ARMOR (DEPRECATED: this makes no sense here)
* String EXTRA_PASSPHRASE (key passphrase)
*/
public static final String ACTION_SIGN = "org.openintents.openpgp.action.SIGN";
/**
* Sign text resulting in a cleartext signature
* Some magic pre-processing of the text is done to convert it to a format usable for
* cleartext signatures per RFC 4880 before the text is actually signed:
* - end cleartext with newline
* - remove whitespaces on line endings
* <p/>
* optional extras:
* String EXTRA_PASSPHRASE (key passphrase)
*/
public static final String ACTION_CLEARTEXT_SIGN = "org.openintents.openpgp.action.CLEARTEXT_SIGN";
/**
* Sign text or binary data resulting in a detached signature.
* No OutputStream necessary for ACTION_DETACHED_SIGN (No magic pre-processing like in ACTION_CLEARTEXT_SIGN)!
* The detached signature is returned separately in RESULT_DETACHED_SIGNATURE.
* <p/>
* optional extras:
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for detached signature)
* String EXTRA_PASSPHRASE (key passphrase)
* <p/>
* returned extras:
* byte[] RESULT_DETACHED_SIGNATURE
*/
public static final String ACTION_DETACHED_SIGN = "org.openintents.openpgp.action.DETACHED_SIGN";
/**
* Encrypt
*
* <p/>
* required extras:
* String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)
* or
* long[] EXTRA_KEY_IDS
*
* <p/>
* optional extras:
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput)
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output)
* String EXTRA_PASSPHRASE (key passphrase)
* String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata)
*/
public static final String ACTION_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT";
/**
* Sign and encrypt
*
* <p/>
* required extras:
* String[] EXTRA_USER_IDS (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)
* or
* long[] EXTRA_KEY_IDS
*
* <p/>
* optional extras:
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput)
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for output)
* String EXTRA_PASSPHRASE (key passphrase)
* String EXTRA_ORIGINAL_FILENAME (original filename to be encrypted as metadata)
*/
public static final String ACTION_SIGN_AND_ENCRYPT = "org.openintents.openpgp.action.SIGN_AND_ENCRYPT";
/**
* Decrypts and verifies given input stream. This methods handles encrypted-only, signed-and-encrypted,
* and also signed-only input.
*
* If OpenPgpSignatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY
* OutputStream is optional, e.g., for verifying detached signatures!
* <p/>
* If OpenPgpSignatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING
* in addition a PendingIntent is returned via RESULT_INTENT to download missing keys.
*
* <p/>
* optional extras:
* boolean EXTRA_REQUEST_ASCII_ARMOR (request ascii armor for ouput)
*
* byte[] EXTRA_DETACHED_SIGNATURE (detached signature)
* <p/>
* returned extras:
* OpenPgpSignatureResult RESULT_SIGNATURE
* OpenPgpDecryptMetadata RESULT_METADATA
* String RESULT_CHARSET (charset which was specified in the headers of ascii armored input, if any)
*/
public static final String ACTION_DECRYPT_VERIFY = "org.openintents.openpgp.action.DECRYPT_VERIFY";
/**
* Decrypts the header of an encrypted file to retrieve metadata such as original filename.
* <p/>
* This does not decrypt the actual content of the file.
* <p/>
* returned extras:
* OpenPgpDecryptMetadata RESULT_METADATA
* String RESULT_CHARSET (charset which was specified in the headers of ascii armored input, if any)
*/
public static final String ACTION_DECRYPT_METADATA = "org.openintents.openpgp.action.DECRYPT_METADATA";
/**
* Get key ids based on given user ids (=emails)
*
* <p/>
* required extras:
* String[] EXTRA_USER_IDS
*
* <p/>
* returned extras:
* long[] EXTRA_KEY_IDS
* long[] RESULT_KEY_IDS
*/
public static final String ACTION_GET_KEY_IDS = "org.openintents.openpgp.action.GET_KEY_IDS";
/**
* This action returns RESULT_CODE_SUCCESS if the OpenPGP Provider already has the key
* corresponding to the given key id in its database.
*
* <p/>
* It returns RESULT_CODE_USER_INTERACTION_REQUIRED if the Provider does not have the key.
* The PendingIntent from RESULT_INTENT can be used to retrieve those from a keyserver.
*
* <p/>
* required extras:
* long EXTRA_KEY_ID
*/
@ -130,19 +195,29 @@ public class OpenPgpApi {
public static final String EXTRA_ACCOUNT_NAME = "account_name";
// SIGN, ENCRYPT, SIGN_AND_ENCRYPT, DECRYPT_VERIFY
// ACTION_DETACHED_SIGN, ENCRYPT, SIGN_AND_ENCRYPT, DECRYPT_VERIFY
// request ASCII Armor for output
// OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53)
public static final String EXTRA_REQUEST_ASCII_ARMOR = "ascii_armor";
// ACTION_DETACHED_SIGN
public static final String RESULT_DETACHED_SIGNATURE = "detached_signature";
// ENCRYPT, SIGN_AND_ENCRYPT
public static final String EXTRA_USER_IDS = "user_ids";
public static final String EXTRA_KEY_IDS = "key_ids";
// optional extras:
public static final String EXTRA_PASSPHRASE = "passphrase";
public static final String EXTRA_ORIGINAL_FILENAME = "original_filename";
// internal NFC states
public static final String EXTRA_NFC_SIGNED_HASH = "nfc_signed_hash";
public static final String EXTRA_NFC_SIG_CREATION_TIMESTAMP = "nfc_sig_creation_timestamp";
public static final String EXTRA_NFC_DECRYPTED_SESSION_KEY = "nfc_decrypted_session_key";
// GET_KEY
public static final String EXTRA_KEY_ID = "key_id";
public static final String RESULT_KEY_IDS = "key_ids";
/* Service Intent returns */
public static final String RESULT_CODE = "result_code";
@ -159,7 +234,12 @@ public class OpenPgpApi {
public static final String RESULT_INTENT = "intent";
// DECRYPT_VERIFY
public static final String EXTRA_DETACHED_SIGNATURE = "detached_signature";
public static final String RESULT_SIGNATURE = "signature";
public static final String RESULT_METADATA = "metadata";
// This will be the charset which was specified in the headers of ascii armored input, if any
public static final String RESULT_CHARSET = "charset";
IOpenPgpService mService;
Context mContext;
@ -211,17 +291,14 @@ public class OpenPgpApi {
}
public Intent executeApi(Intent data, InputStream is, OutputStream os) {
ParcelFileDescriptor input = null;
try {
data.putExtra(EXTRA_API_VERSION, OpenPgpApi.API_VERSION);
Intent result = null;
Intent result;
if (ACTION_GET_KEY_IDS.equals(data.getAction())) {
result = mService.execute(data, null, null);
return result;
} else {
// pipe the input and output
// pipe the input and output
ParcelFileDescriptor input = null;
if (is != null) {
input = ParcelFileDescriptorUtil.pipeFrom(is,
new ParcelFileDescriptorUtil.IThreadListener() {
@ -229,43 +306,43 @@ public class OpenPgpApi {
public void onThreadFinished(Thread thread) {
//Log.d(OpenPgpApi.TAG, "Copy to service finished");
}
});
ParcelFileDescriptor output = ParcelFileDescriptorUtil.pipeTo(os,
}
);
}
ParcelFileDescriptor output = null;
if (os != null) {
output = ParcelFileDescriptorUtil.pipeTo(os,
new ParcelFileDescriptorUtil.IThreadListener() {
@Override
public void onThreadFinished(Thread thread) {
//Log.d(OpenPgpApi.TAG, "Service finished writing!");
}
});
// blocks until result is ready
result = mService.execute(data, input, output);
// close() is required to halt the TransferThread
output.close();
// set class loader to current context to allow unparcelling
// of OpenPgpError and OpenPgpSignatureResult
// http://stackoverflow.com/a/3806769
result.setExtrasClassLoader(mContext.getClassLoader());
return result;
}
);
}
// blocks until result is ready
result = mService.execute(data, input, output);
// close() is required to halt the TransferThread
if (output != null) {
output.close();
}
// TODO: close input?
// set class loader to current context to allow unparcelling
// of OpenPgpError and OpenPgpSignatureResult
// http://stackoverflow.com/a/3806769
result.setExtrasClassLoader(mContext.getClassLoader());
return result;
} catch (Exception e) {
Log.e(OpenPgpApi.TAG, "Exception", e);
Log.e(OpenPgpApi.TAG, "Exception in executeApi call", e);
Intent result = new Intent();
result.putExtra(RESULT_CODE, RESULT_CODE_ERROR);
result.putExtra(RESULT_ERROR,
new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage()));
return result;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
Log.e(OpenPgpApi.TAG, "Failed to close input file descriptor", e);
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,9 +16,6 @@
package org.openintents.openpgp.util;
import java.util.ArrayList;
import java.util.List;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
@ -34,9 +31,11 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.TextView;
import org.openintents.openpgp.R;
import java.util.ArrayList;
import java.util.List;
/**
* Does not extend ListPreference, but is very similar to it!
* http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/preference/ListPreference.java/?v=source
@ -47,6 +46,7 @@ public class OpenPgpListPreference extends DialogPreference {
private static final Intent MARKET_INTENT = new Intent(Intent.ACTION_VIEW, Uri.parse(
String.format(MARKET_INTENT_URI_BASE, OPENKEYCHAIN_PACKAGE)));
private ArrayList<OpenPgpProviderEntry> mLegacyList = new ArrayList<OpenPgpProviderEntry>();
private ArrayList<OpenPgpProviderEntry> mList = new ArrayList<OpenPgpProviderEntry>();
private String mSelectedPackage;
@ -59,6 +59,17 @@ public class OpenPgpListPreference extends DialogPreference {
this(context, null);
}
/**
* Public method to add new entries for legacy applications
*
* @param packageName
* @param simpleName
* @param icon
*/
public void addLegacyProvider(int position, String packageName, String simpleName, Drawable icon) {
mLegacyList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon));
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
mList.clear();
@ -66,8 +77,11 @@ public class OpenPgpListPreference extends DialogPreference {
// add "none"-entry
mList.add(0, new OpenPgpProviderEntry("",
getContext().getString(R.string.openpgp_list_preference_none),
getContext().getResources().getDrawable(R.drawable.ic_action_cancel_launchersize_light)));
getContext().getResources().getDrawable(R.drawable.ic_action_cancel_launchersize)));
// add all additional (legacy) providers
mList.addAll(mLegacyList);
// search for OpenPGP providers...
ArrayList<OpenPgpProviderEntry> providerList = new ArrayList<OpenPgpProviderEntry>();
Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,43 +16,74 @@
package org.openintents.openpgp.util;
import org.openintents.openpgp.IOpenPgpService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import org.openintents.openpgp.IOpenPgpService;
public class OpenPgpServiceConnection {
// callback interface
public interface OnBound {
public void onBound(IOpenPgpService service);
public void onError(Exception e);
}
private Context mApplicationContext;
private boolean mBound;
private IOpenPgpService mService;
private String mProviderPackageName;
private OnBound mOnBoundListener;
/**
* Create new connection
*
* @param context
* @param providerPackageName specify package name of OpenPGP provider,
* e.g., "org.sufficientlysecure.keychain"
*/
public OpenPgpServiceConnection(Context context, String providerPackageName) {
this.mApplicationContext = context.getApplicationContext();
this.mProviderPackageName = providerPackageName;
}
/**
* Create new connection with callback
*
* @param context
* @param providerPackageName specify package name of OpenPGP provider,
* e.g., "org.sufficientlysecure.keychain"
* @param onBoundListener callback, executed when connection to service has been established
*/
public OpenPgpServiceConnection(Context context, String providerPackageName,
OnBound onBoundListener) {
this(context, providerPackageName);
this.mOnBoundListener = onBoundListener;
}
public IOpenPgpService getService() {
return mService;
}
public boolean isBound() {
return mBound;
return (mService != null);
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IOpenPgpService.Stub.asInterface(service);
mBound = true;
if (mOnBoundListener != null) {
mOnBoundListener.onBound(mService);
}
}
public void onServiceDisconnected(ComponentName name) {
mService = null;
mBound = false;
}
};
@ -61,23 +92,28 @@ public class OpenPgpServiceConnection {
*
* @return
*/
public boolean bindToService() {
public void bindToService() {
// if not already bound...
if (mService == null && !mBound) {
if (mService == null) {
try {
Intent serviceIntent = new Intent();
serviceIntent.setAction(IOpenPgpService.class.getName());
Intent serviceIntent = new Intent(OpenPgpApi.SERVICE_INTENT);
// NOTE: setPackage is very important to restrict the intent to this provider only!
serviceIntent.setPackage(mProviderPackageName);
mApplicationContext.bindService(serviceIntent, mServiceConnection,
boolean connect = mApplicationContext.bindService(serviceIntent, mServiceConnection,
Context.BIND_AUTO_CREATE);
return true;
if (!connect) {
throw new Exception("bindService() returned false!");
}
} catch (Exception e) {
return false;
if (mOnBoundListener != null) {
mOnBoundListener.onError(e);
}
}
} else {
return true;
// already bound, but also inform client about it with callback
if (mOnBoundListener != null) {
mOnBoundListener.onBound(mService);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
package org.openintents.openpgp.util;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -61,4 +62,15 @@ public class OpenPgpUtils {
}
}
public static String convertKeyIdToHex(long keyId) {
return "0x" + convertKeyIdToHex32bit(keyId >> 32) + convertKeyIdToHex32bit(keyId);
}
private static String convertKeyIdToHex32bit(long keyId) {
String hexString = Long.toHexString(keyId & 0xffffffffL).toLowerCase(Locale.ENGLISH);
while (hexString.length() < 8) {
hexString = "0" + hexString;
}
return hexString;
}
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* 2013 Flow (http://stackoverflow.com/questions/18212152/transfer-inputstream-to-another-service-across-process-boundaries-with-parcelf)
* Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
* 2013 Florian Schmaus <flo@geekplace.eu>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,6 +23,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Partially based on <a href="http://stackoverflow.com/questions/18212152/">Stackoverflow: Transfer InputStream to another Service (across process boundaries)</a>
**/
public class ParcelFileDescriptorUtil {
public interface IThreadListener {
@ -100,4 +103,4 @@ public class ParcelFileDescriptorUtil {
}
}
}
}
}