diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-02-17 20:03:38 +0100 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-02-17 20:03:38 +0100 |
commit | 2e3d0d444180ef7217e6e960d2092e4f3de4c198 (patch) | |
tree | 778dc901f287fff9aeb1c9d3d41d7053eeccf1b0 /OpenPGP-Keychain/src/main | |
parent | 7b819e65de71a17827a3264a1a8663ca0d30b48c (diff) | |
parent | d3181f4478ce29fc96d101f5f72b4e82c03ec5e0 (diff) | |
download | open-keychain-2e3d0d444180ef7217e6e960d2092e4f3de4c198.tar.gz open-keychain-2e3d0d444180ef7217e6e960d2092e4f3de4c198.tar.bz2 open-keychain-2e3d0d444180ef7217e6e960d2092e4f3de4c198.zip |
Merge pull request #277 from openpgp-keychain/new-api
New api
Diffstat (limited to 'OpenPGP-Keychain/src/main')
14 files changed, 514 insertions, 904 deletions
diff --git a/OpenPGP-Keychain/src/main/AndroidManifest.xml b/OpenPGP-Keychain/src/main/AndroidManifest.xml index 6de35571f..95f148686 100644 --- a/OpenPGP-Keychain/src/main/AndroidManifest.xml +++ b/OpenPGP-Keychain/src/main/AndroidManifest.xml @@ -30,7 +30,7 @@ --> <uses-sdk - android:minSdkVersion="8" + android:minSdkVersion="9" android:targetSdkVersion="19" /> <uses-feature @@ -153,12 +153,19 @@ android:windowSoftInputMode="stateHidden"> <!-- Keychain's own Actions --> + <!-- ENCRYPT with text as extra --> <intent-filter> <action android:name="org.sufficientlysecure.keychain.action.ENCRYPT" /> <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <!-- ENCRYPT with data Uri --> + <intent-filter> + <action android:name="org.sufficientlysecure.keychain.action.ENCRYPT" /> - <data android:mimeType="*/*" /> + <category android:name="android.intent.category.DEFAULT" /> + <!-- TODO: accept other schemes! --> + <data android:scheme="file" /> </intent-filter> <!-- Android's Send Action --> <intent-filter android:label="@string/intent_send_encrypt"> @@ -176,12 +183,19 @@ android:windowSoftInputMode="stateHidden"> <!-- Keychain's own Actions --> + <!-- DECRYPT with text as extra --> <intent-filter> <action android:name="org.sufficientlysecure.keychain.action.DECRYPT" /> <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <!-- DECRYPT with data Uri --> + <intent-filter> + <action android:name="org.sufficientlysecure.keychain.action.DECRYPT" /> - <data android:mimeType="*/*" /> + <category android:name="android.intent.category.DEFAULT" /> + <!-- TODO: accept other schemes! --> + <data android:scheme="file" /> </intent-filter> <!-- Android's Send Action --> <intent-filter android:label="@string/intent_send_decrypt"> @@ -282,6 +296,7 @@ <data android:mimeType="application/pgp-keys" /> </intent-filter> <!-- Keychain's own Actions --> + <!-- IMPORT_KEY with files TODO: does this work? --> <intent-filter android:label="@string/intent_import_key"> <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY" /> @@ -289,11 +304,19 @@ <data android:mimeType="*/*" /> </intent-filter> - <!-- IMPORT again without mimeType to also allow data only without filename --> + <!-- IMPORT_KEY with mimeType 'application/pgp-keys' --> + <intent-filter> + <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY" /> + + <category android:name="android.intent.category.DEFAULT" /> + <!-- mime type as defined in http://tools.ietf.org/html/rfc3156, section 7 --> + <data android:mimeType="application/pgp-keys" /> + </intent-filter> + <!-- IMPORT_KEY without mimeType to allow import with extras Bundle --> <intent-filter android:label="@string/intent_import_key"> <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY" /> <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY_FROM_QR_CODE" /> - <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY_FROM_KEY_SERVER" /> + <action android:name="org.sufficientlysecure.keychain.action.IMPORT_KEY_FROM_KEYSERVER" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> @@ -362,10 +385,9 @@ <activity android:name="org.sufficientlysecure.keychain.service.remote.RemoteServiceActivity" android:exported="false" - android:label="@string/app_name" - android:launchMode="singleTop" - android:process=":remote_api" - android:taskAffinity=":remote_api" /> + android:label="@string/app_name" /> + <!--android:launchMode="singleTop"--> + <!--android:process=":remote_api"--> <activity android:name="org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity" android:configChanges="orientation|screenSize|keyboardHidden|keyboard" @@ -392,19 +414,19 @@ </service> <!-- Extended Remote API --> - <service - android:name="org.sufficientlysecure.keychain.service.remote.ExtendedApiService" - android:enabled="true" - android:exported="true" - android:process=":remote_api"> - <intent-filter> - <action android:name="org.sufficientlysecure.keychain.service.remote.IExtendedApiService" /> - </intent-filter> - - <meta-data - android:name="api_version" - android:value="1" /> - </service> + <!--<service--> + <!--android:name="org.sufficientlysecure.keychain.service.remote.ExtendedApiService"--> + <!--android:enabled="true"--> + <!--android:exported="true"--> + <!--android:process=":remote_api">--> + <!--<intent-filter>--> + <!--<action android:name="org.sufficientlysecure.keychain.service.remote.IExtendedApiService" />--> + <!--</intent-filter>--> + + <!--<meta-data--> + <!--android:name="api_version"--> + <!--android:value="1" />--> + <!--</service>--> <!-- TODO: authority! Make this API with content provider uris --> <!-- <provider --> diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 870e45ea5..1de9ab985 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -235,7 +235,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial String action = intent.getAction(); - // execute action from extra bundle + // executeServiceMethod action from extra bundle if (ACTION_ENCRYPT_SIGN.equals(action)) { try { /* Input */ diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/NoUserIdsException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/NoUserIdsException.java deleted file mode 100644 index 555303238..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/NoUserIdsException.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.sufficientlysecure.keychain.service.exception; - -public class NoUserIdsException extends Exception { - - private static final long serialVersionUID = 7009311527126696207L; - - public NoUserIdsException(String message) { - super(message); - } -}
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/UserInteractionRequiredException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/UserInteractionRequiredException.java deleted file mode 100644 index 1152d6796..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/UserInteractionRequiredException.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.sufficientlysecure.keychain.service.exception; - -public class UserInteractionRequiredException extends Exception { - - private static final long serialVersionUID = -60128148603511936L; - - public UserInteractionRequiredException(String message) { - super(message); - } -}
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPassphraseException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPassphraseException.java deleted file mode 100644 index 14b774eb5..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPassphraseException.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.sufficientlysecure.keychain.service.exception; - -public class WrongPassphraseException extends Exception { - - private static final long serialVersionUID = -5309689232853485740L; - - public WrongPassphraseException(String message) { - super(message); - } -}
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/ExtendedApiService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/ExtendedApiService.java deleted file mode 100644 index 427e6bb8f..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/ExtendedApiService.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.service.remote; - -import java.io.ByteArrayOutputStream; -import java.io.PrintWriter; -import java.security.cert.X509Certificate; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.PasswordCallback; - -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openssl.PEMWriter; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.pgp.PgpToX509; -import org.sufficientlysecure.keychain.util.Log; - -import android.content.Intent; -import android.os.IBinder; -import android.os.RemoteException; - -public class ExtendedApiService extends RemoteService { - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - private void selfSignedX509CertSafe(String subjAltNameURI, IExtendedApiCallback callback, - AppSettings appSettings) { - - // TODO: for pgp keyrings with password - CallbackHandler pgpPwdCallbackHandler = new PgpToX509.PredefinedPasswordCallbackHandler(""); - - try { - long keyId = appSettings.getKeyId(); - PGPSecretKey pgpSecretKey = PgpKeyHelper.getSigningKey(this, keyId); - - PasswordCallback pgpSecKeyPasswordCallBack = new PasswordCallback("pgp passphrase?", - false); - pgpPwdCallbackHandler.handle(new Callback[] { pgpSecKeyPasswordCallBack }); - PGPPrivateKey pgpPrivKey = pgpSecretKey.extractPrivateKey( - pgpSecKeyPasswordCallBack.getPassword(), Constants.BOUNCY_CASTLE_PROVIDER_NAME); - pgpSecKeyPasswordCallBack.clearPassword(); - - X509Certificate selfSignedCert = PgpToX509.createSelfSignedCert(pgpSecretKey, - pgpPrivKey, subjAltNameURI); - - // Write x509cert and privKey into files - // FileOutputStream fosCert = context.openFileOutput(CERT_FILENAME, - // Context.MODE_PRIVATE); - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - PEMWriter pemWriterCert = new PEMWriter(new PrintWriter(outStream)); - pemWriterCert.writeObject(selfSignedCert); - pemWriterCert.close(); - - byte[] outputBytes = outStream.toByteArray(); - - callback.onSuccess(outputBytes); - } catch (Exception e) { - Log.e(Constants.TAG, "ExtendedApiService", e); - try { - callback.onError(e.getMessage()); - } catch (RemoteException e1) { - Log.e(Constants.TAG, "ExtendedApiService", e); - } - } - - // TODO: no private key at the moment! Don't give it to others - // PrivateKey privKey = pgpPrivKey.getKey(); - // FileOutputStream fosKey = context.openFileOutput(PRIV_KEY_FILENAME, - // Context.MODE_PRIVATE); - // PEMWriter pemWriterKey = new PEMWriter(new PrintWriter(fosKey)); - // pemWriterKey.writeObject(privKey); - // pemWriterKey.close(); - } - - private final IExtendedApiService.Stub mBinder = new IExtendedApiService.Stub() { - - @Override - public void encrypt(byte[] inputBytes, String passphrase, IExtendedApiCallback callback) - throws RemoteException { - // TODO : implement - - } - - @Override - public void selfSignedX509Cert(final String subjAltNameURI, - final IExtendedApiCallback callback) throws RemoteException { - final AppSettings settings = getAppSettings(); - - Runnable r = new Runnable() { - @Override - public void run() { - selfSignedX509CertSafe(subjAltNameURI, callback, settings); - } - }; - - checkAndEnqueue(r); - } - - }; - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java index 6db091ed0..31c5662dc 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,108 +17,46 @@ package org.sufficientlysecure.keychain.service.remote; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.regex.Matcher; +import android.app.PendingIntent; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; -import org.openintents.openpgp.IOpenPgpCallback; -import org.openintents.openpgp.IOpenPgpKeyIdsCallback; import org.openintents.openpgp.IOpenPgpService; -import org.openintents.openpgp.OpenPgpData; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; +import org.openintents.openpgp.util.OpenPgpConstants; import org.spongycastle.util.Arrays; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpOperation; -import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.service.exception.NoUserIdsException; -import org.sufficientlysecure.keychain.service.exception.UserInteractionRequiredException; -import org.sufficientlysecure.keychain.service.exception.WrongPassphraseException; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.IBinder; -import android.os.Message; -import android.os.RemoteException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; public class OpenPgpService extends RemoteService { - private String getCachedPassphrase(long keyId, boolean allowUserInteraction) - throws UserInteractionRequiredException { - String passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), keyId); - - if (passphrase == null) { - if (!allowUserInteraction) { - throw new UserInteractionRequiredException( - "Passphrase not found in cache, please enter your passphrase!"); - } - - Log.d(Constants.TAG, "No passphrase! Activity required!"); - - // start passphrase dialog - PassphraseActivityCallback callback = new PassphraseActivityCallback(); - Bundle extras = new Bundle(); - extras.putLong(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId); - pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE, callback, - extras); - - if (callback.isSuccess()) { - Log.d(Constants.TAG, "New passphrase entered!"); - - // get again after it was entered - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), keyId); - } else { - Log.d(Constants.TAG, "Passphrase dialog canceled!"); - - return null; - } - - } - - return passphrase; - } - - public class PassphraseActivityCallback extends UserInputCallback { + private static final int PRIVATE_REQUEST_CODE_PASSPHRASE = 551; + private static final int PRIVATE_REQUEST_CODE_USER_IDS = 552; - private boolean success = false; - - public boolean isSuccess() { - return success; - } - - @Override - public void handleUserInput(Message msg) { - if (msg.arg1 == OKAY) { - success = true; - } else { - success = false; - } - } - }; /** * Search database for key ids based on emails. - * + * * @param encryptionUserIds * @return */ - private long[] getKeyIdsFromEmails(String[] encryptionUserIds, boolean allowUserInteraction) - throws UserInteractionRequiredException { + private Bundle getKeyIdsFromEmails(Bundle params, String[] encryptionUserIds) { // find key ids to given emails in database ArrayList<Long> keyIds = new ArrayList<Long>(); @@ -152,96 +90,118 @@ public class OpenPgpService extends RemoteService { } // allow the user to verify pub key selection - if (allowUserInteraction && (missingUserIdsCheck || dublicateUserIdsCheck)) { - SelectPubKeysActivityCallback callback = new SelectPubKeysActivityCallback(); - - Bundle extras = new Bundle(); - extras.putLongArray(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray); - extras.putStringArrayList(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds); - extras.putStringArrayList(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, - dublicateUserIds); - - pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS, callback, - extras); - - if (callback.isSuccess()) { - Log.d(Constants.TAG, "New selection of pub keys!"); - keyIdsArray = callback.getPubKeyIds(); - } else { - Log.d(Constants.TAG, "Pub key selection canceled!"); - return null; - } - } - - // if no user interaction is allow throw exceptions on duplicate or missing pub keys - if (!allowUserInteraction) { - if (missingUserIdsCheck) - throw new UserInteractionRequiredException( - "Pub keys for these user ids are missing:" + missingUserIds.toString()); - if (dublicateUserIdsCheck) - throw new UserInteractionRequiredException( - "More than one pub key with these user ids exist:" - + dublicateUserIds.toString()); + if (missingUserIdsCheck || dublicateUserIdsCheck) { + // build PendingIntent for passphrase input + Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); + intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS); + intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray); + intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds); + intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds); + intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); + + PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0); + + // return PendingIntent to be executed by client + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); + result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); + + return result; } if (keyIdsArray.length == 0) { return null; } - return keyIdsArray; + + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); + result.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS, keyIdsArray); + return result; } - public class SelectPubKeysActivityCallback extends UserInputCallback { - public static final String PUB_KEY_IDS = "pub_key_ids"; + private Bundle getPassphraseBundleIntent(Bundle params, long keyId) { + // build PendingIntent for passphrase input + Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); + intent.setAction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE); + intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId); + // pass params through to activity that it can be returned again later to repeat pgp operation + intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); + PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0); + + // return PendingIntent to be executed by client + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); + result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); + + return result; + } - private boolean success = false; - private long[] pubKeyIds; - public boolean isSuccess() { - return success; - } - - public long[] getPubKeyIds() { - return pubKeyIds; - } - - @Override - public void handleUserInput(Message msg) { - if (msg.arg1 == OKAY) { - success = true; - pubKeyIds = msg.getData().getLongArray(PUB_KEY_IDS); + // TODO: asciiArmor?! + private Bundle signImpl(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output, + AppSettings appSettings) { + try { + // get passphrase from cache, if key has "no" passphrase, this returns an empty String + String passphrase; + if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) { + passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE); } else { - success = false; + passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId()); + } + if (passphrase == null) { + // get PendingIntent for passphrase input, add it to given params and return to client + Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId()); + return passphraseBundle; } - } - }; - private synchronized void getKeyIdsSafe(String[] userIds, boolean allowUserInteraction, - IOpenPgpKeyIdsCallback callback, AppSettings appSettings) { - try { - long[] keyIds = getKeyIdsFromEmails(userIds, allowUserInteraction); - if (keyIds == null) { - throw new NoUserIdsException("No user ids!"); + // Get Input- and OutputStream from ParcelFileDescriptor + InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); + OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); + try { + long inputLength = is.available(); + InputData inputData = new InputData(is, inputLength); + + PgpOperation operation = new PgpOperation(getContext(), null, inputData, os); + operation.signText(appSettings.getKeyId(), passphrase, appSettings.getHashAlgorithm(), + Preferences.getPreferences(this).getForceV3Signatures()); + } finally { + is.close(); + os.close(); } - callback.onSuccess(keyIds); - } catch (UserInteractionRequiredException e) { - callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage()); - } catch (NoUserIdsException e) { - callbackOpenPgpError(callback, OpenPgpError.NO_USER_IDS, e.getMessage()); + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); + return result; } catch (Exception e) { - callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage()); + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); + result.putParcelable(OpenPgpConstants.RESULT_ERRORS, + new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + return result; } } - private synchronized void encryptAndSignSafe(OpenPgpData inputData, - final OpenPgpData outputData, long[] keyIds, boolean allowUserInteraction, - IOpenPgpCallback callback, AppSettings appSettings, boolean sign) { + private Bundle encryptAndSignImpl(Bundle params, ParcelFileDescriptor input, + ParcelFileDescriptor output, AppSettings appSettings, + boolean sign) { try { - // TODO: other options of OpenPgpData! - byte[] inputBytes = getInput(inputData); - boolean asciiArmor = false; - if (outputData.getType() == OpenPgpData.TYPE_STRING) { - asciiArmor = true; + boolean asciiArmor = params.getBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, false); + + long[] keyIds; + if (params.containsKey(OpenPgpConstants.PARAMS_KEY_IDS)) { + keyIds = params.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS); + } else { + // get key ids based on given user ids + String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS); + // give params through to activity... + Bundle result = getKeyIdsFromEmails(params, userIds); + + if (result.getInt(OpenPgpConstants.RESULT_CODE, 0) == OpenPgpConstants.RESULT_CODE_SUCCESS) { + keyIds = result.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS); + } else { + // if not success -> result contains a PendingIntent for user interaction + return result; + } } // add own key for encryption @@ -249,349 +209,319 @@ public class OpenPgpService extends RemoteService { keyIds[keyIds.length - 1] = appSettings.getKeyId(); // build InputData and write into OutputStream - InputStream inputStream = new ByteArrayInputStream(inputBytes); - long inputLength = inputBytes.length; - InputData inputDt = new InputData(inputStream, inputLength); - - OutputStream outputStream = new ByteArrayOutputStream(); + // Get Input- and OutputStream from ParcelFileDescriptor + InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); + OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); + try { + long inputLength = is.available(); + InputData inputData = new InputData(is, inputLength); + + PgpOperation operation = new PgpOperation(getContext(), null, inputData, os); + if (sign) { + String passphrase; + if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) { + passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE); + } else { + passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), + appSettings.getKeyId()); + } + if (passphrase == null) { + // get PendingIntent for passphrase input, add it to given params and return to client + Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId()); + return passphraseBundle; + } - PgpOperation operation = new PgpOperation(getContext(), null, inputDt, outputStream); - if (sign) { - String passphrase = getCachedPassphrase(appSettings.getKeyId(), - allowUserInteraction); - if (passphrase == null) { - throw new WrongPassphraseException("No or wrong passphrase!"); + operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null, + appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(), + appSettings.getHashAlgorithm(), true, passphrase); + } else { + operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null, + appSettings.getEncryptionAlgorithm(), Id.key.none, + appSettings.getHashAlgorithm(), true, null); } - - operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null, - appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(), - appSettings.getHashAlgorithm(), true, passphrase); - } else { - operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null, - appSettings.getEncryptionAlgorithm(), Id.key.none, - appSettings.getHashAlgorithm(), true, null); + } finally { + is.close(); + os.close(); } - outputStream.close(); - - byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); - - OpenPgpData output = null; - if (asciiArmor) { - output = new OpenPgpData(new String(outputBytes)); - } else { - output = new OpenPgpData(outputBytes); - } - - // return over handler on client side - callback.onSuccess(output, null); - } catch (UserInteractionRequiredException e) { - callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage()); - } catch (WrongPassphraseException e) { - callbackOpenPgpError(callback, OpenPgpError.NO_OR_WRONG_PASSPHRASE, e.getMessage()); - } catch (Exception e) { - callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage()); - } - } - - // TODO: asciiArmor?! - private void signSafe(byte[] inputBytes, boolean allowUserInteraction, - IOpenPgpCallback callback, AppSettings appSettings) { - try { - // build InputData and write into OutputStream - InputStream inputStream = new ByteArrayInputStream(inputBytes); - long inputLength = inputBytes.length; - InputData inputData = new InputData(inputStream, inputLength); - - OutputStream outputStream = new ByteArrayOutputStream(); - - String passphrase = getCachedPassphrase(appSettings.getKeyId(), allowUserInteraction); - if (passphrase == null) { - throw new WrongPassphraseException("No or wrong passphrase!"); - } - - PgpOperation operation = new PgpOperation(getContext(), null, inputData, outputStream); - operation.signText(appSettings.getKeyId(), passphrase, appSettings.getHashAlgorithm(), - Preferences.getPreferences(this).getForceV3Signatures()); - - outputStream.close(); - - byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); - OpenPgpData output = new OpenPgpData(new String(outputBytes)); - - // return over handler on client side - callback.onSuccess(output, null); - } catch (UserInteractionRequiredException e) { - callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage()); - } catch (WrongPassphraseException e) { - callbackOpenPgpError(callback, OpenPgpError.NO_OR_WRONG_PASSPHRASE, e.getMessage()); + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); + return result; } catch (Exception e) { - callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage()); + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); + result.putParcelable(OpenPgpConstants.RESULT_ERRORS, + new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + return result; } } - private synchronized void decryptAndVerifySafe(byte[] inputBytes, boolean allowUserInteraction, - IOpenPgpCallback callback, AppSettings appSettings) { + private Bundle decryptAndVerifyImpl(Bundle params, ParcelFileDescriptor input, + ParcelFileDescriptor output, AppSettings appSettings) { try { - // TODO: this is not really needed - // checked if it is text with BEGIN and END tags - String message = new String(inputBytes); - Log.d(Constants.TAG, "in: " + message); - boolean signedOnly = false; - Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(message); - if (matcher.matches()) { - Log.d(Constants.TAG, "PGP_MESSAGE matched"); - message = matcher.group(1); - // replace non breakable spaces - message = message.replaceAll("\\xa0", " "); - - // overwrite inputBytes - inputBytes = message.getBytes(); - } else { - matcher = PgpHelper.PGP_SIGNED_MESSAGE.matcher(message); - if (matcher.matches()) { - signedOnly = true; - Log.d(Constants.TAG, "PGP_SIGNED_MESSAGE matched"); - message = matcher.group(1); - // replace non breakable spaces - message = message.replaceAll("\\xa0", " "); - - // overwrite inputBytes - inputBytes = message.getBytes(); + // Get Input- and OutputStream from ParcelFileDescriptor + InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); + OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); + OpenPgpSignatureResult sigResult = null; + try { + + + // TODOs API 2.0: + // implement verify-only! + // fix the mess: http://stackoverflow.com/questions/148130/how-do-i-peek-at-the-first-two-bytes-in-an-inputstream + // should we allow to decrypt everything under every key id or only the one set? + // TODO: instead of trying to get the passphrase before + // pause stream when passphrase is missing and then resume + + + // TODO: this is not really needed + // checked if it is text with BEGIN and END tags +// String message = new String(inputBytes); +// Log.d(Constants.TAG, "in: " + message); + boolean signedOnly = false; +// Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(message); +// if (matcher.matches()) { +// Log.d(Constants.TAG, "PGP_MESSAGE matched"); +// message = matcher.group(1); +// // replace non breakable spaces +// message = message.replaceAll("\\xa0", " "); +// +// // overwrite inputBytes +// inputBytes = message.getBytes(); +// } else { +// matcher = PgpHelper.PGP_SIGNED_MESSAGE.matcher(message); +// if (matcher.matches()) { +// signedOnly = true; +// Log.d(Constants.TAG, "PGP_SIGNED_MESSAGE matched"); +// message = matcher.group(1); +// // replace non breakable spaces +// message = message.replaceAll("\\xa0", " "); +// +// // overwrite inputBytes +// inputBytes = message.getBytes(); +// } else { +// Log.d(Constants.TAG, "Nothing matched! Binary?"); +// } +// } + // END TODO + +// Log.d(Constants.TAG, "in: " + new String(inputBytes)); + + // TODO: This allows to decrypt messages with ALL secret keys, not only the one for the + // app, Fix this? + +// String passphrase = null; +// if (!signedOnly) { +// // BEGIN Get key +// // TODO: this input stream is consumed after PgpMain.getDecryptionKeyId()... do it +// // better! +// InputStream inputStream2 = new ByteArrayInputStream(inputBytes); +// +// // TODO: duplicates functions from DecryptActivity! +// long secretKeyId; +// try { +// if (inputStream2.markSupported()) { +// // should probably set this to the max size of two +// // pgpF objects, if it even needs to be anything other +// // than 0. +// inputStream2.mark(200); +// } +// secretKeyId = PgpHelper.getDecryptionKeyId(this, inputStream2); +// if (secretKeyId == Id.key.none) { +// throw new PgpGeneralException(getString(R.string.error_no_secret_key_found)); +// } +// } catch (NoAsymmetricEncryptionException e) { +// if (inputStream2.markSupported()) { +// inputStream2.reset(); +// } +// secretKeyId = Id.key.symmetric; +// if (!PgpOperation.hasSymmetricEncryption(this, inputStream2)) { +// throw new PgpGeneralException( +// getString(R.string.error_no_known_encryption_found)); +// } +// // we do not support symmetric decryption from the API! +// throw new Exception("Symmetric decryption is not supported!"); +// } +// +// Log.d(Constants.TAG, "secretKeyId " + secretKeyId); + + // NOTE: currently this only gets the passphrase for the saved key + String passphrase; + if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) { + passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE); } else { - Log.d(Constants.TAG, "Nothing matched! Binary?"); + passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId()); } - } - // END TODO - - Log.d(Constants.TAG, "in: " + new String(inputBytes)); - - // TODO: This allows to decrypt messages with ALL secret keys, not only the one for the - // app, Fix this? - - String passphrase = null; - if (!signedOnly) { - // BEGIN Get key - // TODO: this input stream is consumed after PgpMain.getDecryptionKeyId()... do it - // better! - InputStream inputStream2 = new ByteArrayInputStream(inputBytes); - - // TODO: duplicates functions from DecryptActivity! - long secretKeyId; - try { - if (inputStream2.markSupported()) { - // should probably set this to the max size of two - // pgpF objects, if it even needs to be anything other - // than 0. - inputStream2.mark(200); - } - secretKeyId = PgpHelper.getDecryptionKeyId(this, inputStream2); - if (secretKeyId == Id.key.none) { - throw new PgpGeneralException(getString(R.string.error_no_secret_key_found)); - } - } catch (NoAsymmetricEncryptionException e) { - if (inputStream2.markSupported()) { - inputStream2.reset(); - } - secretKeyId = Id.key.symmetric; - if (!PgpOperation.hasSymmetricEncryption(this, inputStream2)) { - throw new PgpGeneralException( - getString(R.string.error_no_known_encryption_found)); - } - // we do not support symmetric decryption from the API! - throw new Exception("Symmetric decryption is not supported!"); + if (passphrase == null) { + // get PendingIntent for passphrase input, add it to given params and return to client + Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId()); + return passphraseBundle; } +// } - Log.d(Constants.TAG, "secretKeyId " + secretKeyId); + // build InputData and write into OutputStream + long inputLength = is.available(); + InputData inputData = new InputData(is, inputLength); - passphrase = getCachedPassphrase(secretKeyId, allowUserInteraction); - if (passphrase == null) { - throw new WrongPassphraseException("No or wrong passphrase!"); - } - } - // build InputData and write into OutputStream - InputStream inputStream = new ByteArrayInputStream(inputBytes); - long inputLength = inputBytes.length; - InputData inputData = new InputData(inputStream, inputLength); + Bundle outputBundle; + PgpOperation operation = new PgpOperation(getContext(), null, inputData, os); + if (signedOnly) { + outputBundle = operation.verifyText(); + } else { + // BIG TODO: instead of trying to get the passphrase before + // pause stream when passphrase is missing and then resume + outputBundle = operation.decryptAndVerify(passphrase, false); + } - OutputStream outputStream = new ByteArrayOutputStream(); +// outputStream.close(); - Bundle outputBundle; - PgpOperation operation = new PgpOperation(getContext(), null, inputData, outputStream); - if (signedOnly) { - outputBundle = operation.verifyText(); - } else { - outputBundle = operation.decryptAndVerify(passphrase, false); - } +// byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); - outputStream.close(); + // get signature informations from bundle + boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE); - byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); + if (signature) { + long signatureKeyId = outputBundle + .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID); + String signatureUserId = outputBundle + .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID); + boolean signatureSuccess = outputBundle + .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS); + boolean signatureUnknown = outputBundle + .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN); - // get signature informations from bundle - boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE); + int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR; + if (signatureSuccess) { + signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED; + } else if (signatureUnknown) { + signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY; + } - OpenPgpSignatureResult sigResult = null; - if (signature) { - long signatureKeyId = outputBundle - .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID); - String signatureUserId = outputBundle - .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID); - boolean signatureSuccess = outputBundle - .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS); - boolean signatureUnknown = outputBundle - .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN); - - int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR; - if (signatureSuccess) { - signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_TRUSTED; - } else if (signatureUnknown) { - signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY; + sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId, + signedOnly, signatureKeyId); } - - sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId, - signedOnly, signatureKeyId); + } finally { + is.close(); + os.close(); } - OpenPgpData output = new OpenPgpData(new String(outputBytes)); - - // return over handler on client side - callback.onSuccess(output, sigResult); - } catch (UserInteractionRequiredException e) { - callbackOpenPgpError(callback, OpenPgpError.USER_INTERACTION_REQUIRED, e.getMessage()); - } catch (WrongPassphraseException e) { - callbackOpenPgpError(callback, OpenPgpError.NO_OR_WRONG_PASSPHRASE, e.getMessage()); + + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); + result.putParcelable(OpenPgpConstants.RESULT_SIGNATURE, sigResult); + return result; } catch (Exception e) { - callbackOpenPgpError(callback, OpenPgpError.GENERIC_ERROR, e.getMessage()); + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); + result.putParcelable(OpenPgpConstants.RESULT_ERRORS, + new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + return result; } } + private Bundle getKeyIdsImpl(Bundle params) { + // get key ids based on given user ids + String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS); + Bundle result = getKeyIdsFromEmails(params, userIds); + return result; + } + /** - * Returns error to IOpenPgpCallback - * - * @param callback - * @param errorId - * @param message + * Checks that params != null and API version fits + * + * @param params + * @return */ - private void callbackOpenPgpError(IOpenPgpCallback callback, int errorId, String message) { - try { - callback.onError(new OpenPgpError(0, message)); - } catch (Exception t) { - Log.e(Constants.TAG, - "Exception while returning OpenPgpError to client via callback.onError()", t); + private Bundle checkRequirements(Bundle params) { + // params Bundle is required! + if (params == null) { + Bundle result = new Bundle(); + OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!"); + result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); + return result; } - } - private void callbackOpenPgpError(IOpenPgpKeyIdsCallback callback, int errorId, String message) { - try { - callback.onError(new OpenPgpError(0, message)); - } catch (Exception t) { - Log.e(Constants.TAG, - "Exception while returning OpenPgpError to client via callback.onError()", t); + // version code is required and needs to correspond to version code of service! + if (params.getInt(OpenPgpConstants.PARAMS_API_VERSION) != OpenPgpConstants.API_VERSION) { + Bundle result = new Bundle(); + OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!"); + result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); + return result; } + + // check if caller is allowed to access openpgp keychain + Bundle result = isAllowed(params); + if (result != null) { + return result; + } + + return null; } + // TODO: multi-threading private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() { @Override - public void encrypt(final OpenPgpData input, final OpenPgpData output, final long[] keyIds, - final IOpenPgpCallback callback) throws RemoteException { - final AppSettings settings = getAppSettings(); - - Runnable r = new Runnable() { - @Override - public void run() { - encryptAndSignSafe(input, output, keyIds, true, callback, settings, false); - } - }; + public Bundle sign(Bundle params, final ParcelFileDescriptor input, final ParcelFileDescriptor output) { + final AppSettings appSettings = getAppSettings(); - checkAndEnqueue(r); - } - - @Override - public void signAndEncrypt(final OpenPgpData input, final OpenPgpData output, - final long[] keyIds, final IOpenPgpCallback callback) throws RemoteException { - final AppSettings settings = getAppSettings(); - - Runnable r = new Runnable() { - @Override - public void run() { - encryptAndSignSafe(input, output, keyIds, true, callback, settings, true); - } - }; + Bundle errorResult = checkRequirements(params); + if (errorResult != null) { + return errorResult; + } - checkAndEnqueue(r); + return signImpl(params, input, output, appSettings); } @Override - public void sign(final OpenPgpData input, final OpenPgpData output, - final IOpenPgpCallback callback) throws RemoteException { - final AppSettings settings = getAppSettings(); - - Runnable r = new Runnable() { - @Override - public void run() { - signSafe(getInput(input), true, callback, settings); - } - }; + public Bundle encrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) { + final AppSettings appSettings = getAppSettings(); + + Bundle errorResult = checkRequirements(params); + if (errorResult != null) { + return errorResult; + } - checkAndEnqueue(r); + return encryptAndSignImpl(params, input, output, appSettings, false); } @Override - public void decryptAndVerify(final OpenPgpData input, final OpenPgpData output, - final IOpenPgpCallback callback) throws RemoteException { + public Bundle signAndEncrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) { + final AppSettings appSettings = getAppSettings(); - final AppSettings settings = getAppSettings(); - - Runnable r = new Runnable() { - @Override - public void run() { - decryptAndVerifySafe(getInput(input), true, callback, settings); - } - }; + Bundle errorResult = checkRequirements(params); + if (errorResult != null) { + return errorResult; + } - checkAndEnqueue(r); + return encryptAndSignImpl(params, input, output, appSettings, true); } @Override - public void getKeyIds(final String[] userIds, final boolean allowUserInteraction, - final IOpenPgpKeyIdsCallback callback) throws RemoteException { - - final AppSettings settings = getAppSettings(); + public Bundle decryptAndVerify(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) { + final AppSettings appSettings = getAppSettings(); - Runnable r = new Runnable() { - @Override - public void run() { - getKeyIdsSafe(userIds, allowUserInteraction, callback, settings); - } - }; + Bundle errorResult = checkRequirements(params); + if (errorResult != null) { + return errorResult; + } - checkAndEnqueue(r); + return decryptAndVerifyImpl(params, input, output, appSettings); } - }; - - private static byte[] getInput(OpenPgpData data) { - // TODO: support Uri and ParcelFileDescriptor - - byte[] inBytes = null; - switch (data.getType()) { - case OpenPgpData.TYPE_STRING: - inBytes = data.getString().getBytes(); - break; - - case OpenPgpData.TYPE_BYTE_ARRAY: - inBytes = data.getBytes(); - break; + @Override + public Bundle getKeyIds(Bundle params) { + Bundle errorResult = checkRequirements(params); + if (errorResult != null) { + return errorResult; + } - default: - Log.e(Constants.TAG, "Uri and ParcelFileDescriptor not supported right now!"); - break; + return getKeyIdsImpl(params); } - return inBytes; - } + }; @Override public IBinder onBind(Intent intent) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java index bc513d532..cfd2b9ec3 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,17 +19,16 @@ package org.sufficientlysecure.keychain.service.remote; import java.util.ArrayList; import java.util.Arrays; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.TimeUnit; +import org.openintents.openpgp.OpenPgpError; +import org.openintents.openpgp.util.OpenPgpConstants; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.exception.WrongPackageSignatureException; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.PausableThreadPoolExecutor; +import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; @@ -50,66 +49,19 @@ import android.os.Messenger; public abstract class RemoteService extends Service { Context mContext; - private final ArrayBlockingQueue<Runnable> mPoolQueue = new ArrayBlockingQueue<Runnable>(100); - // TODO: Are these parameters okay? - private PausableThreadPoolExecutor mThreadPool = new PausableThreadPoolExecutor(2, 4, 10, - TimeUnit.SECONDS, mPoolQueue); + private static final int PRIVATE_REQUEST_CODE_REGISTER = 651; + private static final int PRIVATE_REQUEST_CODE_ERROR = 652; - private final Object userInputLock = new Object(); - - /** - * Override handleUserInput() to handle OKAY (1) and CANCEL (0). After handling the waiting - * threads will be notified and the queue resumed - */ - protected class UserInputCallback extends BaseCallback { - - public void handleUserInput(Message msg) { - } - - @Override - public boolean handleMessage(Message msg) { - handleUserInput(msg); - - // resume - synchronized (userInputLock) { - userInputLock.notifyAll(); - } - mThreadPool.resume(); - return true; - } - - } - - /** - * Extends Handler.Callback with OKAY (1), CANCEL (0) variables - */ - private class BaseCallback implements Handler.Callback { - public static final int OKAY = 1; - public static final int CANCEL = 0; - - @Override - public boolean handleMessage(Message msg) { - return false; - } - - } public Context getContext() { return mContext; } - /** - * Should be used from Stub implementations of AIDL interfaces to enqueue a runnable for - * execution - * - * @param r - */ - protected void checkAndEnqueue(Runnable r) { + protected Bundle isAllowed(Bundle params) { try { if (isCallerAllowed(false)) { - mThreadPool.execute(r); - Log.d(Constants.TAG, "Enqueued runnable…"); + return null; } else { String[] callingPackages = getPackageManager().getPackagesForUid( Binder.getCallingUid()); @@ -121,32 +73,46 @@ public abstract class RemoteService extends Service { packageSignature = getPackageSignature(packageName); } catch (NameNotFoundException e) { Log.e(Constants.TAG, "Should not happen, returning!", e); - return; - } - Log.e(Constants.TAG, - "Not allowed to use service! Starting activity for registration!"); - Bundle extras = new Bundle(); - extras.putString(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName); - extras.putByteArray(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature); - RegisterActivityCallback callback = new RegisterActivityCallback(); - - pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_REGISTER, callback, - extras); - - if (callback.isAllowed()) { - mThreadPool.execute(r); - Log.d(Constants.TAG, "Enqueued runnable…"); - } else { - Log.d(Constants.TAG, "User disallowed app!"); + // return error + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); + result.putParcelable(OpenPgpConstants.RESULT_ERRORS, + new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + return result; } + Log.e(Constants.TAG, "Not allowed to use service! return PendingIntent for registration!"); + + Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); + intent.setAction(RemoteServiceActivity.ACTION_REGISTER); + intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName); + intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature); + intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); + + PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_REGISTER, intent, 0); + + // return PendingIntent to be executed by client + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); + result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); + + return result; } } catch (WrongPackageSignatureException e) { - Log.e(Constants.TAG, e.getMessage()); + Log.e(Constants.TAG, "wrong signature!", e); + + Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); + intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE); + intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, getString(R.string.api_error_wrong_signature)); + intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); + + PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_ERROR, intent, 0); + + // return PendingIntent to be executed by client + Bundle result = new Bundle(); + result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); + result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); - Bundle extras = new Bundle(); - extras.putString(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, - getString(R.string.api_error_wrong_signature)); - pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_ERROR_MESSAGE, null, extras); + return result; } } @@ -161,40 +127,8 @@ public abstract class RemoteService extends Service { } /** - * Locks current thread and pauses execution of runnables and starts activity for user input - * - * @param action - * @param messenger - * @param extras - */ - protected void pauseAndStartUserInteraction(String action, BaseCallback callback, Bundle extras) { - synchronized (userInputLock) { - mThreadPool.pause(); - - Log.d(Constants.TAG, "starting activity..."); - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setAction(action); - - Messenger messenger = new Messenger(new Handler(getMainLooper(), callback)); - - extras.putParcelable(RemoteServiceActivity.EXTRA_MESSENGER, messenger); - intent.putExtras(extras); - - startActivity(intent); - - // lock current thread for user input - try { - userInputLock.wait(); - } catch (InterruptedException e) { - Log.e(Constants.TAG, "CryptoService", e); - } - } - } - - /** * Retrieves AppSettings from database for the application calling this remote service - * + * * @return */ protected AppSettings getAppSettings() { @@ -215,66 +149,11 @@ public abstract class RemoteService extends Service { return null; } - class RegisterActivityCallback extends BaseCallback { - public static final String PACKAGE_NAME = "package_name"; - - private boolean allowed = false; - private String packageName; - - public boolean isAllowed() { - return allowed; - } - - public String getPackageName() { - return packageName; - } - - @Override - public boolean handleMessage(Message msg) { - if (msg.arg1 == OKAY) { - allowed = true; - packageName = msg.getData().getString(PACKAGE_NAME); - - // resume threads - try { - if (isPackageAllowed(packageName)) { - synchronized (userInputLock) { - userInputLock.notifyAll(); - } - mThreadPool.resume(); - } else { - // Should not happen! - Log.e(Constants.TAG, "Should not happen! Emergency shutdown!"); - mThreadPool.shutdownNow(); - } - } catch (WrongPackageSignatureException e) { - Log.e(Constants.TAG, e.getMessage()); - - Bundle extras = new Bundle(); - extras.putString(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, - getString(R.string.api_error_wrong_signature)); - pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_ERROR_MESSAGE, null, - extras); - } - } else { - allowed = false; - - synchronized (userInputLock) { - userInputLock.notifyAll(); - } - mThreadPool.resume(); - } - return true; - } - - } - /** * Checks if process that binds to this service (i.e. the package name corresponding to the * process) is in the list of allowed package names. - * - * @param allowOnlySelf - * allow only Keychain app itself + * + * @param allowOnlySelf allow only Keychain app itself * @return true if process is allowed to use this service * @throws WrongPackageSignatureException */ @@ -308,7 +187,7 @@ public abstract class RemoteService extends Service { /** * Checks if packageName is a registered app for the API. Does not return true for own package! - * + * * @param packageName * @return * @throws WrongPackageSignatureException diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java index 7ab39fce1..af8e3ade8 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,8 +17,15 @@ package org.sufficientlysecure.keychain.service.remote; -import java.util.ArrayList; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; +import android.support.v7.app.ActionBarActivity; +import android.view.View; +import org.openintents.openpgp.util.OpenPgpConstants; import org.sufficientlysecure.htmltextview.HtmlTextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; @@ -30,15 +37,7 @@ import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment; import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; import org.sufficientlysecure.keychain.util.Log; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.support.v7.app.ActionBarActivity; -import android.view.View; -import android.widget.Toast; +import java.util.ArrayList; public class RemoteServiceActivity extends ActionBarActivity { @@ -64,17 +63,11 @@ public class RemoteServiceActivity extends ActionBarActivity { // error message public static final String EXTRA_ERROR_MESSAGE = "error_message"; - private Messenger mMessenger; - // register view private AppSettingsFragment mSettingsFragment; // select pub keys view private SelectPublicKeyFragment mSelectFragment; - // has the user clicked one of the buttons - // or do we need to handle the callback in onStop() - private boolean finishHandled; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -82,36 +75,12 @@ public class RemoteServiceActivity extends ActionBarActivity { handleActions(getIntent(), savedInstanceState); } - @Override - protected void onStop() { - super.onStop(); - - if (!finishHandled) { - Message msg = Message.obtain(); - msg.arg1 = RemoteService.RegisterActivityCallback.CANCEL; - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } - } - } - protected void handleActions(Intent intent, Bundle savedInstanceState) { - finishHandled = false; String action = intent.getAction(); - Bundle extras = intent.getExtras(); + final Bundle extras = intent.getExtras(); - if (extras == null) { - extras = new Bundle(); - } - mMessenger = extras.getParcelable(EXTRA_MESSENGER); - - /** - * com.android.crypto actions - */ if (ACTION_REGISTER.equals(action)) { final String packageName = extras.getString(EXTRA_PACKAGE_NAME); final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE); @@ -131,37 +100,21 @@ public class RemoteServiceActivity extends ActionBarActivity { ProviderHelper.insertApiApp(RemoteServiceActivity.this, mSettingsFragment.getAppSettings()); - Message msg = Message.obtain(); - msg.arg1 = RemoteService.RegisterActivityCallback.OKAY; - Bundle data = new Bundle(); - data.putString(RemoteService.RegisterActivityCallback.PACKAGE_NAME, - packageName); - msg.setData(data); - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } - - finishHandled = true; - finish(); + // give params through for new service call + Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS); + + Intent finishIntent = new Intent(); + finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, oldParams); + RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent); + RemoteServiceActivity.this.finish(); } } }, R.string.api_register_disallow, new View.OnClickListener() { @Override public void onClick(View v) { // Disallow - - Message msg = Message.obtain(); - msg.arg1 = RemoteService.RegisterActivityCallback.CANCEL; - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } - - finishHandled = true; - finish(); + RemoteServiceActivity.this.setResult(RESULT_CANCELED); + RemoteServiceActivity.this.finish(); } } ); @@ -175,8 +128,9 @@ public class RemoteServiceActivity extends ActionBarActivity { mSettingsFragment.setAppSettings(settings); } else if (ACTION_CACHE_PASSPHRASE.equals(action)) { long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID); + Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS); - showPassphraseDialog(secretKeyId); + showPassphraseDialog(oldParams, secretKeyId); } else if (ACTION_SELECT_PUB_KEYS.equals(action)) { long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); ArrayList<String> missingUserIds = intent @@ -184,8 +138,8 @@ public class RemoteServiceActivity extends ActionBarActivity { ArrayList<String> dublicateUserIds = intent .getStringArrayListExtra(EXTRA_DUBLICATE_USER_IDS); - String text = new String(); - text += "<b>" + getString(R.string.api_select_pub_keys_text) + "</b>"; + // TODO: do this with spannable instead of HTML to prevent parsing failures with weird user ids + String text = "<b>" + getString(R.string.api_select_pub_keys_text) + "</b>"; text += "<br/><br/>"; if (missingUserIds != null && missingUserIds.size() > 0) { text += getString(R.string.api_select_pub_keys_missing_text); @@ -212,40 +166,22 @@ public class RemoteServiceActivity extends ActionBarActivity { new View.OnClickListener() { @Override public void onClick(View v) { - // ok - - Message msg = Message.obtain(); - msg.arg1 = OpenPgpService.SelectPubKeysActivityCallback.OKAY; - Bundle data = new Bundle(); - data.putLongArray( - OpenPgpService.SelectPubKeysActivityCallback.PUB_KEY_IDS, + // add key ids to params Bundle for new request + Bundle params = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS); + params.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS, mSelectFragment.getSelectedMasterKeyIds()); - msg.setData(data); - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } - finishHandled = true; - finish(); + Intent finishIntent = new Intent(); + finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); + RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent); + RemoteServiceActivity.this.finish(); } }, R.string.btn_do_not_save, new View.OnClickListener() { @Override public void onClick(View v) { // cancel - - Message msg = Message.obtain(); - msg.arg1 = OpenPgpService.SelectPubKeysActivityCallback.CANCEL; - ; - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } - - finishHandled = true; - finish(); + RemoteServiceActivity.this.setResult(RESULT_CANCELED); + RemoteServiceActivity.this.finish(); } } ); @@ -278,8 +214,7 @@ public class RemoteServiceActivity extends ActionBarActivity { } else if (ACTION_ERROR_MESSAGE.equals(action)) { String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE); - String text = new String(); - text += "<font color=\"red\">" + errorMessage + "</font>"; + String text = "<font color=\"red\">" + errorMessage + "</font>"; // Inflate a "Done" custom action bar view ActionBarHelper.setDoneView(getSupportActionBar(), R.string.btn_okay, @@ -287,7 +222,8 @@ public class RemoteServiceActivity extends ActionBarActivity { @Override public void onClick(View v) { - finish(); + RemoteServiceActivity.this.setResult(RESULT_OK); + RemoteServiceActivity.this.finish(); } }); @@ -297,7 +233,8 @@ public class RemoteServiceActivity extends ActionBarActivity { HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_app_error_message_text); textView.setHtmlFromString(text); } else { - Log.e(Constants.TAG, "Wrong action!"); + Log.e(Constants.TAG, "Action does not exist!"); + setResult(RESULT_CANCELED); finish(); } } @@ -307,31 +244,21 @@ public class RemoteServiceActivity extends ActionBarActivity { * encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks * for a symmetric passphrase */ - private void showPassphraseDialog(long secretKeyId) { + private void showPassphraseDialog(final Bundle params, long secretKeyId) { // Message is received after passphrase is cached Handler returnHandler = new Handler() { @Override public void handleMessage(Message message) { if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - Message msg = Message.obtain(); - msg.arg1 = OpenPgpService.PassphraseActivityCallback.OKAY; - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } + // return given params again, for calling the service method again + Intent finishIntent = new Intent(); + finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); + RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent); } else { - Message msg = Message.obtain(); - msg.arg1 = OpenPgpService.PassphraseActivityCallback.CANCEL; - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "CryptoServiceActivity", e); - } + RemoteServiceActivity.this.setResult(RESULT_CANCELED); } - finishHandled = true; - finish(); + RemoteServiceActivity.this.finish(); } }; @@ -344,9 +271,12 @@ public class RemoteServiceActivity extends ActionBarActivity { passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog"); } catch (PgpGeneralException e) { - Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!"); - // send message to handler to start encryption directly - returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY); + Log.d(Constants.TAG, "No passphrase for this secret key, do pgp operation directly!"); + // return given params again, for calling the service method again + Intent finishIntent = new Intent(); + finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); + setResult(RESULT_OK, finishIntent); + finish(); } } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java index cef002265..cc08548e8 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/WrongPackageSignatureException.java @@ -1,4 +1,4 @@ -package org.sufficientlysecure.keychain.service.exception; +package org.sufficientlysecure.keychain.service.remote; public class WrongPackageSignatureException extends Exception { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 3dd077d12..b8eed83c9 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -300,7 +300,7 @@ public class DecryptActivity extends DrawerActivity { String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); if (sharedText != null) { // handle like normal text decryption, override action and extras to later - // execute ACTION_DECRYPT in main actions + // executeServiceMethod ACTION_DECRYPT in main actions extras.putString(EXTRA_TEXT, sharedText); action = ACTION_DECRYPT; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 81446db99..85bfba224 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -173,7 +173,7 @@ public class EncryptActivity extends DrawerActivity { String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); if (sharedText != null) { // handle like normal text encryption, override action and extras to later - // execute ACTION_ENCRYPT in main actions + // executeServiceMethod ACTION_ENCRYPT in main actions extras.putString(EXTRA_TEXT, sharedText); extras.putBoolean(EXTRA_ASCII_ARMOR, true); action = ACTION_ENCRYPT; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index e0f25b632..1864e0d9d 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -57,6 +57,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa + "IMPORT_KEY_FROM_QR_CODE"; public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_KEYSERVER"; + // TODO: implement: public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN"; diff --git a/OpenPGP-Keychain/src/main/res/values/strings.xml b/OpenPGP-Keychain/src/main/res/values/strings.xml index 88ad10a0a..d34fe0105 100644 --- a/OpenPGP-Keychain/src/main/res/values/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values/strings.xml @@ -295,7 +295,7 @@ <string name="progress_saving">saving…</string> <string name="progress_importing">importing…</string> <string name="progress_exporting">exporting…</string> - <string name="progress_generating">generating key, this can take a while…</string> + <string name="progress_generating">generating key, this can take up to 3 minutes…</string> <string name="progress_building_key">building key…</string> <string name="progress_preparing_master_key">preparing master key…</string> <string name="progress_certifying_master_key">certifying master key…</string> @@ -383,7 +383,7 @@ <string name="api_settings_revoke">Revoke access</string> <string name="api_settings_package_name">Package Name</string> <string name="api_settings_package_signature">SHA-256 of Package Signature</string> - <string name="api_register_text">The following application requests access to OpenPGP Keychain.\n\nAllow permanent access?</string> + <string name="api_register_text">The displayed application requests access to OpenPGP Keychain.\nAllow access?\n\nWARNING: If you do not know why this screen appeared, disallow access! You can revoke access later using the \'Registered Applications\' screen.</string> <string name="api_register_allow">Allow access</string> <string name="api_register_disallow">Disallow access</string> <string name="api_register_error_select_key">Please select a key!</string> |