From fcd27d2600711ccd32c000c6d58da19cb816a9bf Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Thu, 9 Jul 2015 22:51:20 +0530 Subject: implemented revocation on deletion --- OpenKeychain/src/main/AndroidManifest.xml | 6 + .../keychain/operations/DeleteOperation.java | 18 +- .../keychain/operations/EditKeyOperation.java | 33 ++- .../keychain/operations/ExportOperation.java | 27 ++- .../keychain/operations/RevokeOperation.java | 124 ++++++++++ .../keychain/operations/results/DeleteResult.java | 16 +- .../keychain/operations/results/EditKeyResult.java | 2 +- .../operations/results/InputPendingResult.java | 10 +- .../operations/results/OperationResult.java | 7 + .../keychain/operations/results/RevokeResult.java | 100 ++++++++ .../keychain/pgp/UncachedKeyRing.java | 5 +- .../keychain/service/ExportKeyringParcel.java | 11 + .../keychain/service/KeychainService.java | 5 +- .../keychain/service/RevokeKeyringParcel.java | 47 ++++ .../keychain/service/SaveKeyringParcel.java | 34 +++ .../keychain/service/input/CryptoInputParcel.java | 9 +- .../service/input/RequiredInputParcel.java | 2 +- .../keychain/ui/DeleteKeyDialogActivity.java | 231 ++++++++++++++++++ .../keychain/ui/EditKeyFragment.java | 1 + .../keychain/ui/KeyListFragment.java | 70 +++--- .../keychain/ui/RevokeDeleteDialogActivity.java | 258 +++++++++++++++++++++ .../keychain/ui/ViewKeyActivity.java | 50 ++-- .../keychain/ui/base/CryptoOperationHelper.java | 34 +-- .../ui/dialog/DeleteKeyDialogFragment.java | 211 ----------------- .../src/main/res/layout/del_rev_dialog.xml | 24 ++ OpenKeychain/src/main/res/values/arrays.xml | 4 + OpenKeychain/src/main/res/values/strings.xml | 25 ++ 27 files changed, 1059 insertions(+), 305 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RevokeDeleteDialogActivity.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java create mode 100644 OpenKeychain/src/main/res/layout/del_rev_dialog.xml (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index 93c75cca6..7e4f13db5 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -682,6 +682,12 @@ + + diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java index ac4a0da11..63c613aa6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java @@ -18,19 +18,29 @@ package org.sufficientlysecure.keychain.operations; import android.content.Context; +import android.net.Uri; import android.support.annotation.NonNull; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; import org.sufficientlysecure.keychain.operations.results.DeleteResult; +import org.sufficientlysecure.keychain.operations.results.InputPendingResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.service.DeleteKeyringParcel; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; /** An operation which implements a high level keyring delete operation. * @@ -48,12 +58,17 @@ public class DeleteOperation extends BaseOperation { @NonNull @Override - public DeleteResult execute(DeleteKeyringParcel deleteKeyringParcel, + public OperationResult execute(DeleteKeyringParcel deleteKeyringParcel, CryptoInputParcel cryptoInputParcel) { long[] masterKeyIds = deleteKeyringParcel.mMasterKeyIds; boolean isSecret = deleteKeyringParcel.mIsSecret; + return onlyDeleteKey(masterKeyIds, isSecret); + } + + private DeleteResult onlyDeleteKey(long[] masterKeyIds, boolean isSecret) { + OperationLog log = new OperationLog(); if (masterKeyIds.length == 0) { @@ -113,7 +128,6 @@ public class DeleteOperation extends BaseOperation { } return new DeleteResult(result, log, success, fail); - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java index eafbff4bc..f8f7e79a3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -21,7 +21,10 @@ import android.content.Context; import android.support.annotation.NonNull; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; +import org.sufficientlysecure.keychain.operations.results.ExportResult; +import org.sufficientlysecure.keychain.operations.results.InputPendingResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; @@ -34,6 +37,7 @@ import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; +import org.sufficientlysecure.keychain.service.ExportKeyringParcel; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -58,8 +62,16 @@ public class EditKeyOperation extends BaseOperation { super(context, providerHelper, progressable, cancelled); } + /** + * Saves an edited key, and uploads it to a server atomically or otherwise as + * specified in saveParcel + * + * @param saveParcel primary input to the operation + * @param cryptoInput input that changes if user interaction is required + * @return the result of the operation + */ @NonNull - public OperationResult execute(SaveKeyringParcel saveParcel, CryptoInputParcel cryptoInput) { + public InputPendingResult execute(SaveKeyringParcel saveParcel, CryptoInputParcel cryptoInput) { OperationLog log = new OperationLog(); log.add(LogType.MSG_ED, 0); @@ -120,6 +132,24 @@ public class EditKeyOperation extends BaseOperation { // It's a success, so this must be non-null now UncachedKeyRing ring = modifyResult.getRing(); + if (saveParcel.isUpload()) { + ExportKeyringParcel exportKeyringParcel = + new ExportKeyringParcel(saveParcel.getUploadKeyserver(), ring); + ExportResult uploadResult = + new ExportOperation(mContext, mProviderHelper, mProgressable) + .execute(exportKeyringParcel, cryptoInput); + if (uploadResult.isPending()) { + return uploadResult; + } else if (!uploadResult.success() && saveParcel.isUploadAtomic()) { + // if atomic, update fail implies edit operation should also fail and not save + log.add(uploadResult, 2); + return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, saveParcel.mMasterKeyId); + } else { + // upload succeeded or not atomic so we continue + log.add(uploadResult, 2); + } + } + // Save the new keyring. SaveKeyringResult saveResult = mProviderHelper .saveSecretKeyRing(ring, new ProgressScaler(mProgressable, 60, 95, 100)); @@ -160,5 +190,4 @@ public class EditKeyOperation extends BaseOperation { return new EditKeyResult(EditKeyResult.RESULT_OK, log, ring.getMasterKeyId()); } - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java index 56ed4ef58..0dec35949 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java @@ -34,6 +34,7 @@ import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.text.TextUtils; import org.spongycastle.bcpg.ArmoredOutputStream; @@ -42,6 +43,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException; import org.sufficientlysecure.keychain.operations.results.ExportResult; +import org.sufficientlysecure.keychain.operations.results.InputPendingResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; @@ -128,6 +130,18 @@ public class ExportOperation extends BaseOperation { } } + /** + * returns null if no user input required for upload, an InputPendingResult otherwise + */ + @Nullable + public InputPendingResult getUploadPendingInput() { + if (!OrbotHelper.isOrbotInRequiredState(mContext)) { + return new ExportResult(null, + RequiredInputParcel.createOrbotRequiredOperation()); + } + return null; + } + public ExportResult exportToFile(long[] masterKeyIds, boolean exportSecret, String outputFile) { OperationLog log = new OperationLog(); @@ -351,10 +365,15 @@ public class ExportOperation extends BaseOperation { HkpKeyserver hkpKeyserver = new HkpKeyserver(exportInput.mKeyserver); try { - CanonicalizedPublicKeyRing keyring - = mProviderHelper.getCanonicalizedPublicKeyRing( - exportInput.mCanonicalizedPublicKeyringUri); - return uploadKeyRingToServer(hkpKeyserver, keyring, proxy); + if (exportInput.mCanonicalizedPublicKeyringUri != null) { + CanonicalizedPublicKeyRing keyring + = mProviderHelper.getCanonicalizedPublicKeyRing( + exportInput.mCanonicalizedPublicKeyringUri); + return uploadKeyRingToServer(hkpKeyserver, keyring, proxy); + } else { + return uploadKeyRingToServer(hkpKeyserver, exportInput.mUncachedKeyRing, + proxy); + } } catch (ProviderHelper.NotFoundException e) { Log.e(Constants.TAG, "error uploading key", e); return new ExportResult(ExportResult.RESULT_ERROR, new OperationLog()); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java new file mode 100644 index 000000000..157e36e04 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java @@ -0,0 +1,124 @@ +package org.sufficientlysecure.keychain.operations; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.support.annotation.NonNull; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.operations.results.DeleteResult; +import org.sufficientlysecure.keychain.operations.results.InputPendingResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.operations.results.RevokeResult; +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.RevokeKeyringParcel; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; + +public class RevokeOperation extends BaseOperation { + + public RevokeOperation(Context context, ProviderHelper providerHelper, Progressable progressable) { + super(context, providerHelper, progressable); + } + + @NonNull + @Override + public OperationResult execute(RevokeKeyringParcel revokeKeyringParcel, + CryptoInputParcel cryptoInputParcel) { + + long masterKeyId = revokeKeyringParcel.mMasterKeyId; + + OperationResult.OperationLog log = new OperationResult.OperationLog(); + log.add(OperationResult.LogType.MSG_REVOKE, 0, + KeyFormattingUtils.beautifyKeyId(masterKeyId)); + + try { + + Uri secretUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(masterKeyId); + CachedPublicKeyRing keyRing = mProviderHelper.getCachedPublicKeyRing(secretUri); + + // check if this is a master secret key we can work with + switch (keyRing.getSecretKeyType(masterKeyId)) { + case GNU_DUMMY: + log.add(OperationResult.LogType.MSG_EK_ERROR_DUMMY, 1); + return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId); + } + + SaveKeyringParcel saveKeyringParcel = getRevokedSaveKeyringParcel(masterKeyId, + keyRing.getFingerprint()); + + // all revoke operations are made atomic as of now + saveKeyringParcel.setUpdateOptions(revokeKeyringParcel.mUpload, true, + revokeKeyringParcel.mKeyserver); + + InputPendingResult revokeAndUploadResult = new EditKeyOperation(mContext, + mProviderHelper, mProgressable, mCancelled) + .execute(saveKeyringParcel, cryptoInputParcel); + + if (revokeAndUploadResult.isPending()) { + return revokeAndUploadResult; + } + + log.add(revokeAndUploadResult, 1); + + if (revokeAndUploadResult.success()) { + log.add(OperationResult.LogType.MSG_REVOKE_OK, 1); + return new RevokeResult(RevokeResult.RESULT_OK, log, masterKeyId); + } else { + log.add(OperationResult.LogType.MSG_REVOKE_KEY_FAIL, 1); + return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId); + } + + } catch (PgpKeyNotFoundException | ProviderHelper.NotFoundException e) { + Log.e(Constants.TAG, "could not find key to revoke", e); + log.add(OperationResult.LogType.MSG_REVOKE_KEY_FAIL, 1); + return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId); + } + } + + private SaveKeyringParcel getRevokedSaveKeyringParcel(long masterKeyId, byte[] fingerprint) { + final String[] SUBKEYS_PROJECTION = new String[]{ + KeychainContract.Keys.KEY_ID + }; + final int INDEX_KEY_ID = 0; + + Uri keysUri = KeychainContract.Keys.buildKeysUri(masterKeyId); + Cursor subKeyCursor = + mContext.getContentResolver().query(keysUri, SUBKEYS_PROJECTION, null, null, null); + + SaveKeyringParcel saveKeyringParcel = + new SaveKeyringParcel(masterKeyId, fingerprint); + + // add all subkeys, for revocation + while (subKeyCursor != null && subKeyCursor.moveToNext()) { + saveKeyringParcel.mRevokeSubKeys.add(subKeyCursor.getLong(INDEX_KEY_ID)); + } + if (subKeyCursor != null) { + subKeyCursor.close(); + } + + final String[] USER_IDS_PROJECTION = new String[]{ + KeychainContract.UserPackets.USER_ID + }; + final int INDEX_USER_ID = 0; + + Uri userIdsUri = KeychainContract.UserPackets.buildUserIdsUri(masterKeyId); + Cursor userIdCursor = mContext.getContentResolver().query( + userIdsUri, USER_IDS_PROJECTION, null, null, null); + + while (userIdCursor != null && userIdCursor.moveToNext()) { + saveKeyringParcel.mRevokeUserIds.add(userIdCursor.getString(INDEX_USER_ID)); + } + if (userIdCursor != null) { + userIdCursor.close(); + } + + return saveKeyringParcel; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java index 52ff8bf44..52c6e1491 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java @@ -21,8 +21,10 @@ package org.sufficientlysecure.keychain.operations.results; import android.app.Activity; import android.content.Intent; import android.os.Parcel; +import android.support.annotation.Nullable; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.LogDisplayActivity; import org.sufficientlysecure.keychain.ui.LogDisplayFragment; import org.sufficientlysecure.keychain.ui.util.Notify; @@ -30,7 +32,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; import org.sufficientlysecure.keychain.ui.util.Notify.Showable; import org.sufficientlysecure.keychain.ui.util.Notify.Style; -public class DeleteResult extends OperationResult { +public class DeleteResult extends InputPendingResult { final public int mOk, mFail; @@ -40,6 +42,18 @@ public class DeleteResult extends OperationResult { mFail = fail; } + /** + * used when more input is required + * @param log operation log upto point of required input, if any + * @param requiredInput represents input required + */ + public DeleteResult(@Nullable OperationLog log, RequiredInputParcel requiredInput) { + super(log, requiredInput); + // values are not to be used + mOk = -1; + mFail = -1; + } + /** Construct from a parcel - trivial because we have no extra data. */ public DeleteResult(Parcel source) { super(source); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java index 842b75c3b..b9407a864 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java @@ -20,7 +20,7 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; -public class EditKeyResult extends OperationResult { +public class EditKeyResult extends InputPendingResult { public final Long mMasterKeyId; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java index 0b7aa6d03..5b982ca61 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import android.os.Parcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; public class InputPendingResult extends OperationResult { @@ -30,26 +31,33 @@ public class InputPendingResult extends OperationResult { public static final int RESULT_PENDING = RESULT_ERROR + 8; final RequiredInputParcel mRequiredInput; + // in case operation needs to add to/changes the cryptoInputParcel sent to it + final CryptoInputParcel mCryptoInputParcel; public InputPendingResult(int result, OperationLog log) { super(result, log); mRequiredInput = null; + mCryptoInputParcel = null; } - public InputPendingResult(OperationLog log, RequiredInputParcel requiredInput) { + public InputPendingResult(OperationLog log, RequiredInputParcel requiredInput, + CryptoInputParcel cryptoInputParcel) { super(RESULT_PENDING, log); mRequiredInput = requiredInput; + mCryptoInputParcel = cryptoInputParcel; } public InputPendingResult(Parcel source) { super(source); mRequiredInput = source.readParcelable(getClass().getClassLoader()); + mCryptoInputParcel = source.readParcelable(getClass().getClassLoader()); } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeParcelable(mRequiredInput, 0); + dest.writeParcelable(mCryptoInputParcel, 0); } public boolean isPending() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 88d04350c..5105b7fdc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -760,6 +760,13 @@ public abstract class OperationResult implements Parcelable { MSG_DEL_OK (LogLevel.OK, R.plurals.msg_del_ok), MSG_DEL_FAIL (LogLevel.WARN, R.plurals.msg_del_fail), + MSG_REVOKE_ERROR_EMPTY (LogLevel.ERROR, R.string.msg_revoke_error_empty), + MSG_REVOKE_ERROR_MULTI_SECRET (LogLevel.DEBUG, R.string.msg_revoke_error_multi_secret), + MSG_REVOKE_ERROR_NOT_FOUND (LogLevel.DEBUG, R.string.msg_revoke_error_multi_secret), + MSG_REVOKE (LogLevel.DEBUG, R.string.msg_revoke_key), + MSG_REVOKE_KEY_FAIL (LogLevel.WARN, R.string.msg_revoke_key_fail), + MSG_REVOKE_OK (LogLevel.OK, R.string.msg_revoke_ok), + // keybase verification MSG_KEYBASE_VERIFICATION(LogLevel.START, R.string.msg_keybase_verification), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java new file mode 100644 index 000000000..4b4892b05 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java @@ -0,0 +1,100 @@ +package org.sufficientlysecure.keychain.operations.results; + +import android.app.Activity; +import android.content.Intent; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.Nullable; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; +import org.sufficientlysecure.keychain.ui.LogDisplayActivity; +import org.sufficientlysecure.keychain.ui.LogDisplayFragment; +import org.sufficientlysecure.keychain.ui.util.Notify; + +public class RevokeResult extends InputPendingResult { + + public final long mMasterKeyId; + + public RevokeResult(int result, OperationLog log, long masterKeyId) { + super(result, log); + mMasterKeyId = masterKeyId; + } + + /** + * used when more input is required + * @param log operation log upto point of required input, if any + * @param requiredInput represents input required + */ + public RevokeResult(@Nullable OperationLog log, RequiredInputParcel requiredInput) { + super(log, requiredInput); + // we won't use these values + mMasterKeyId = -1; + } + + /** Construct from a parcel - trivial because we have no extra data. */ + public RevokeResult(Parcel source) { + super(source); + mMasterKeyId = source.readLong(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeLong(mMasterKeyId); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public RevokeResult createFromParcel(Parcel in) { + return new RevokeResult(in); + } + + @Override + public RevokeResult[] newArray(int size) { + return new RevokeResult[size]; + } + }; + + @Override + public Notify.Showable createNotify(final Activity activity) { + + int resultType = getResult(); + + String str; + int duration; + Notify.Style style; + + // Not an overall failure + if ((resultType & OperationResult.RESULT_ERROR) == 0) { + + duration = Notify.LENGTH_LONG; + + // New and updated keys + if (resultType == OperationResult.RESULT_OK) { + style = Notify.Style.OK; + str = activity.getString(R.string.revoke_ok); + } else { + duration = 0; + style = Notify.Style.ERROR; + str = "internal error"; + } + + } else { + duration = 0; + style = Notify.Style.ERROR; + str = activity.getString(R.string.revoke_fail); + } + + return Notify.create(activity, str, duration, style, new Notify.ActionListener() { + @Override + public void onAction() { + Intent intent = new Intent( + activity, LogDisplayActivity.class); + intent.putExtra(LogDisplayFragment.EXTRA_RESULT, RevokeResult.this); + activity.startActivity(intent); + } + }, R.string.snackbar_details); + + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index 7be61d9c8..f4a8fa494 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -18,6 +18,8 @@ package org.sufficientlysecure.keychain.pgp; +import android.os.Parcelable; + import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.PublicKeyAlgorithmTags; import org.spongycastle.bcpg.SignatureSubpacketTags; @@ -48,6 +50,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -78,7 +81,7 @@ import java.util.TreeSet; * */ @SuppressWarnings("unchecked") -public class UncachedKeyRing { +public class UncachedKeyRing implements Serializable { final PGPKeyRing mRing; final boolean mIsSecret; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java index ef5b48df3..a8b901ab0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java @@ -23,9 +23,12 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; + public class ExportKeyringParcel implements Parcelable { public String mKeyserver; public Uri mCanonicalizedPublicKeyringUri; + public UncachedKeyRing mUncachedKeyRing; public boolean mExportSecret; public long mMasterKeyIds[]; @@ -45,6 +48,12 @@ public class ExportKeyringParcel implements Parcelable { mCanonicalizedPublicKeyringUri = keyringUri; } + public ExportKeyringParcel(String keyserver, UncachedKeyRing uncachedKeyRing) { + mExportType = ExportType.UPLOAD_KEYSERVER; + mKeyserver = keyserver; + mUncachedKeyRing = uncachedKeyRing; + } + public ExportKeyringParcel(long[] masterKeyIds, boolean exportSecret, String outputFile) { mExportType = ExportType.EXPORT_FILE; mMasterKeyIds = masterKeyIds; @@ -62,6 +71,7 @@ public class ExportKeyringParcel implements Parcelable { protected ExportKeyringParcel(Parcel in) { mKeyserver = in.readString(); mCanonicalizedPublicKeyringUri = (Uri) in.readValue(Uri.class.getClassLoader()); + mUncachedKeyRing = (UncachedKeyRing) in.readValue(UncachedKeyRing.class.getClassLoader()); mExportSecret = in.readByte() != 0x00; mOutputFile = in.readString(); mOutputUri = (Uri) in.readValue(Uri.class.getClassLoader()); @@ -78,6 +88,7 @@ public class ExportKeyringParcel implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(mKeyserver); dest.writeValue(mCanonicalizedPublicKeyringUri); + dest.writeValue(mUncachedKeyRing); dest.writeByte((byte) (mExportSecret ? 0x01 : 0x00)); dest.writeString(mOutputFile); dest.writeValue(mOutputUri); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java index 1cd76b462..dca2a08c2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java @@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.operations.ExportOperation; import org.sufficientlysecure.keychain.operations.ImportOperation; import org.sufficientlysecure.keychain.operations.KeybaseVerificationOperation; import org.sufficientlysecure.keychain.operations.PromoteKeyOperation; +import org.sufficientlysecure.keychain.operations.RevokeOperation; import org.sufficientlysecure.keychain.operations.SignEncryptOperation; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; @@ -114,6 +115,8 @@ public class KeychainService extends Service implements Progressable { } else if (inputParcel instanceof SaveKeyringParcel) { op = new EditKeyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled); + } else if (inputParcel instanceof RevokeKeyringParcel) { + op = new RevokeOperation(outerThis, new ProviderHelper(outerThis), outerThis); } else if (inputParcel instanceof CertifyActionsParcel) { op = new CertifyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled); @@ -135,7 +138,7 @@ public class KeychainService extends Service implements Progressable { op = new KeybaseVerificationOperation(outerThis, new ProviderHelper(outerThis), outerThis); } else { - return; + throw new AssertionError("Unrecognized input parcel in KeychainService!"); } @SuppressWarnings("unchecked") // this is unchecked, we make sure it's the correct op above! diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java new file mode 100644 index 000000000..b5da31c59 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java @@ -0,0 +1,47 @@ +package org.sufficientlysecure.keychain.service; + +import android.os.Parcel; +import android.os.Parcelable; + +public class RevokeKeyringParcel implements Parcelable { + + final public long mMasterKeyId; + final public boolean mUpload; + final public String mKeyserver; + + public RevokeKeyringParcel(long masterKeyId, boolean upload, String keyserver) { + mMasterKeyId = masterKeyId; + mUpload = upload; + mKeyserver = keyserver; + } + + protected RevokeKeyringParcel(Parcel in) { + mMasterKeyId = in.readLong(); + mUpload = in.readByte() != 0x00; + mKeyserver = in.readString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(mMasterKeyId); + dest.writeByte((byte) (mUpload ? 0x01 : 0x00)); + dest.writeString(mKeyserver); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public RevokeKeyringParcel createFromParcel(Parcel in) { + return new RevokeKeyringParcel(in); + } + + @Override + public RevokeKeyringParcel[] newArray(int size) { + return new RevokeKeyringParcel[size]; + } + }; +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index 679f4f817..fcb95493b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -65,6 +65,11 @@ public class SaveKeyringParcel implements Parcelable { public Passphrase mCardPin; public Passphrase mCardAdminPin; + // private because they have to be set together with setUpdateOptions + private boolean mUpload; + private boolean mUploadAtomic; + private String mKeyserver; + public SaveKeyringParcel() { reset(); } @@ -86,6 +91,27 @@ public class SaveKeyringParcel implements Parcelable { mRevokeSubKeys = new ArrayList<>(); mCardPin = null; mCardAdminPin = null; + mUpload = false; + mUploadAtomic = false; + mKeyserver = null; + } + + public void setUpdateOptions(boolean upload, boolean uploadAtomic, String keysever) { + mUpload = upload; + mUploadAtomic = uploadAtomic; + mKeyserver = keysever; + } + + public boolean isUpload() { + return mUpload; + } + + public boolean isUploadAtomic() { + return mUploadAtomic; + } + + public String getUploadKeyserver() { + return mKeyserver; } public boolean isEmpty() { @@ -234,6 +260,10 @@ public class SaveKeyringParcel implements Parcelable { mCardPin = source.readParcelable(Passphrase.class.getClassLoader()); mCardAdminPin = source.readParcelable(Passphrase.class.getClassLoader()); + + mUpload = source.readByte() != 0; + mUploadAtomic = source.readByte() != 0; + mKeyserver = source.readString(); } @Override @@ -259,6 +289,10 @@ public class SaveKeyringParcel implements Parcelable { destination.writeParcelable(mCardPin, flags); destination.writeParcelable(mCardAdminPin, flags); + + destination.writeByte((byte) (mUpload ? 1 : 0)); + destination.writeByte((byte) (mUploadAtomic ? 1 : 0)); + destination.writeString(mKeyserver); } public static final Creator CREATOR = new Creator() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java index 96f54dd2f..d4cebe67c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java @@ -36,6 +36,8 @@ public class CryptoInputParcel implements Parcelable { final Date mSignatureTime; final Passphrase mPassphrase; // used to supply an explicit proxy to operations that require it + // this is not final so it can be added to an existing CryptoInputParcel + // (e.g) CertifyOperation with upload might require both passphrase and orbot to be enabled private ParcelableProxy mParcelableProxy; // this map contains both decrypted session keys and signed hashes to be @@ -45,30 +47,25 @@ public class CryptoInputParcel implements Parcelable { public CryptoInputParcel() { mSignatureTime = new Date(); mPassphrase = null; - mParcelableProxy = null; } public CryptoInputParcel(Date signatureTime, Passphrase passphrase) { mSignatureTime = signatureTime == null ? new Date() : signatureTime; mPassphrase = passphrase; - mParcelableProxy = null; } public CryptoInputParcel(Passphrase passphrase) { mSignatureTime = new Date(); mPassphrase = passphrase; - mParcelableProxy = null; } public CryptoInputParcel(Date signatureTime) { mSignatureTime = signatureTime == null ? new Date() : signatureTime; mPassphrase = null; - mParcelableProxy = null; } public CryptoInputParcel(ParcelableProxy parcelableProxy) { - mSignatureTime = new Date(); // just for compatibility with parcel-ing - mPassphrase = null; + this(); mParcelableProxy = parcelableProxy; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java index e378296a5..8eef8de8d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java @@ -15,7 +15,7 @@ import java.util.Date; public class RequiredInputParcel implements Parcelable { public enum RequiredInputType { - PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_MOVE_KEY_TO_CARD, ENABLE_ORBOT + PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_MOVE_KEY_TO_CARD, ENABLE_ORBOT, } public Date mSignatureTime; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java new file mode 100644 index 000000000..064d34e38 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -0,0 +1,231 @@ +package org.sufficientlysecure.keychain.ui; + +import android.app.Dialog; +import android.content.DialogInterface; +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.v4.app.DialogFragment; +import android.support.v4.app.FragmentActivity; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.DeleteResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.DeleteKeyringParcel; +import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; +import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.HashMap; + +public class DeleteKeyDialogActivity extends FragmentActivity + implements CryptoOperationHelper.Callback { + public static final String EXTRA_DELETE_MASTER_KEY_IDS = "extra_delete_master_key_ids"; + + private CryptoOperationHelper mDeleteOpHelper; + + private long[] mMasterKeyIds; + private boolean mHasSecret; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mDeleteOpHelper = new CryptoOperationHelper<>(DeleteKeyDialogActivity.this, + DeleteKeyDialogActivity.this, R.string.progress_deleting); + mDeleteOpHelper.onRestoreInstanceState(savedInstanceState); + + mMasterKeyIds = getIntent().getLongArrayExtra(EXTRA_DELETE_MASTER_KEY_IDS); + + Handler deleteDialogHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == DeleteKeyDialogFragment.MESSAGE_PERFORM_DELETE) { + mHasSecret = msg.getData().getBoolean(DeleteKeyDialogFragment.MSG_HAS_SECRET); + mDeleteOpHelper.cryptoOperation(); + } + } + }; + + Messenger messenger = new Messenger(deleteDialogHandler); + + DeleteKeyDialogFragment deleteKeyDialogFragment + = DeleteKeyDialogFragment.newInstance(messenger, mMasterKeyIds); + + deleteKeyDialogFragment.show(getSupportFragmentManager(), "deleteKeyDialog"); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + mDeleteOpHelper.handleActivityResult(requestCode, resultCode, data); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mDeleteOpHelper.onSaveInstanceState(outState); + } + + @Override + public DeleteKeyringParcel createOperationInput() { + return new DeleteKeyringParcel(mMasterKeyIds, mHasSecret); + } + + @Override + public void onCryptoOperationSuccess(DeleteResult result) { + handleResult(result); + } + + @Override + public void onCryptoOperationCancelled() { + setResult(RESULT_CANCELED); + finish(); + } + + @Override + public void onCryptoOperationError(DeleteResult result) { + handleResult(result); + } + + @Override + public boolean onCryptoSetProgress(String msg, int progress, int max) { + return false; + } + + public void handleResult(DeleteResult result) { + Intent intent = new Intent(); + intent.putExtra(OperationResult.EXTRA_RESULT, result); + setResult(RESULT_OK, intent); + finish(); + } + + public static class DeleteKeyDialogFragment extends DialogFragment { + + public static final String MSG_HAS_SECRET = "msg_has_secret"; + + private static final String ARG_MESSENGER = "messenger"; + private static final String ARG_DELETE_MASTER_KEY_IDS = "delete_master_key_ids"; + + public static final int MESSAGE_PERFORM_DELETE = 1; + + private TextView mMainMessage; + private View mInflateView; + + private Messenger mMessenger; + /** + * Creates new instance of this delete file dialog fragment + */ + public static DeleteKeyDialogFragment newInstance(Messenger messenger, long[] masterKeyIds) { + DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment(); + Bundle args = new Bundle(); + + args.putParcelable(ARG_MESSENGER, messenger); + args.putLongArray(ARG_DELETE_MASTER_KEY_IDS, masterKeyIds); + + frag.setArguments(args); + + return frag; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final FragmentActivity activity = getActivity(); + mMessenger = getArguments().getParcelable(ARG_MESSENGER); + + final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS); + + ContextThemeWrapper theme = new ContextThemeWrapper(activity, + R.style.Theme_AppCompat_Light_Dialog); + + CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(theme); + + // Setup custom View to display in AlertDialog + LayoutInflater inflater = activity.getLayoutInflater(); + mInflateView = inflater.inflate(R.layout.view_key_delete_fragment, null); + builder.setView(mInflateView); + + mMainMessage = (TextView) mInflateView.findViewById(R.id.mainMessage); + + final boolean hasSecret; + + // If only a single key has been selected + if (masterKeyIds.length == 1) { + long masterKeyId = masterKeyIds[0]; + + try { + HashMap data = new ProviderHelper(activity).getUnifiedData( + masterKeyId, new String[]{ + KeychainContract.KeyRings.USER_ID, + KeychainContract.KeyRings.HAS_ANY_SECRET + }, new int[]{ + ProviderHelper.FIELD_TYPE_STRING, + ProviderHelper.FIELD_TYPE_INTEGER + } + ); + String name; + KeyRing.UserId mainUserId = KeyRing.splitUserId((String) data.get(KeychainContract.KeyRings.USER_ID)); + if (mainUserId.name != null) { + name = mainUserId.name; + } else { + name = getString(R.string.user_id_no_name); + } + hasSecret = ((Long) data.get(KeychainContract.KeyRings.HAS_ANY_SECRET)) == 1; + + if (hasSecret) { + // show title only for secret key deletions, + // see http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior + builder.setTitle(getString(R.string.title_delete_secret_key, name)); + mMainMessage.setText(getString(R.string.secret_key_deletion_confirmation, name)); + } else { + mMainMessage.setText(getString(R.string.public_key_deletetion_confirmation, name)); + } + } catch (ProviderHelper.NotFoundException e) { + dismiss(); + return null; + } + } else { + mMainMessage.setText(R.string.key_deletion_confirmation_multi); + hasSecret = false; + } + + builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + Bundle data = new Bundle(); + data.putBoolean(MSG_HAS_SECRET, hasSecret); + Message msg = Message.obtain(); + msg.setData(data); + msg.what = MESSAGE_PERFORM_DELETE; + try { + mMessenger.send(msg); + } catch (RemoteException e) { + Log.e(Constants.TAG, "messenger error", e); + } + } + }); + + builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int id) { + getActivity().finish(); + } + }); + + return builder.show(); + } + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index 4e9c5a836..f750c6d97 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -410,6 +410,7 @@ public class EditKeyFragment extends QueueingCryptoOperationFragment { static final int REQUEST_ACTION = 1; + private static final int REQUEST_DELETE = 2; + private static final int REQUEST_VIEW_KEY = 3; private KeyListAdapter mAdapter; private StickyListHeadersListView mStickyList; @@ -336,7 +338,7 @@ public class KeyListFragment extends LoaderFragment Intent viewIntent = new Intent(getActivity(), ViewKeyActivity.class); viewIntent.setData( KeyRings.buildGenericKeyRingUri(mAdapter.getMasterKeyId(position))); - startActivity(viewIntent); + startActivityForResult(viewIntent, REQUEST_VIEW_KEY); } protected void encrypt(ActionMode mode, long[] masterKeyIds) { @@ -362,30 +364,9 @@ public class KeyListFragment extends LoaderFragment return; } - // Message is received after key is deleted - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.arg1 == DeleteKeyDialogFragment.MESSAGE_OKAY) { - Bundle data = message.getData(); - if (data != null) { - DeleteResult result = data.getParcelable(DeleteResult.EXTRA_RESULT); - if (result != null) { - result.createNotify(getActivity()).show(); - } - } - mode.finish(); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, - masterKeyIds); - - deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog"); + Intent intent = new Intent(getActivity(), DeleteKeyDialogActivity.class); + intent.putExtra(DeleteKeyDialogActivity.EXTRA_DELETE_MASTER_KEY_IDS, masterKeyIds); + startActivityForResult(intent, REQUEST_DELETE); } @@ -620,14 +601,35 @@ public class KeyListFragment extends LoaderFragment mConsolidateOpHelper.handleActivityResult(requestCode, resultCode, data); } - if (requestCode == REQUEST_ACTION) { - // if a result has been returned, display a notify - if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { - OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); - result.createNotify(getActivity()).show(); - } else { - super.onActivityResult(requestCode, resultCode, data); - } + switch (requestCode) { + case REQUEST_DELETE: + mActionMode.finish(); + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + result.createNotify(getActivity()).show(); + } else { + super.onActivityResult(requestCode, resultCode, data); + } + break; + + case REQUEST_ACTION: + // if a result has been returned, display a notify + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + result.createNotify(getActivity()).show(); + } else { + super.onActivityResult(requestCode, resultCode, data); + } + break; + + case REQUEST_VIEW_KEY: + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + result.createNotify(getActivity()).show(); + } else { + super.onActivityResult(requestCode, resultCode, data); + } + break; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RevokeDeleteDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RevokeDeleteDialogActivity.java new file mode 100644 index 000000000..b60003419 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RevokeDeleteDialogActivity.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * Copyright (C) 2015 Adithya Abraham Philip + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentActivity; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.AdapterView; +import android.widget.Spinner; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.DeleteResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.operations.results.RevokeResult; +import org.sufficientlysecure.keychain.service.DeleteKeyringParcel; +import org.sufficientlysecure.keychain.service.RevokeKeyringParcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; +import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; + +public class RevokeDeleteDialogActivity extends FragmentActivity { + + public static final String EXTRA_MASTER_KEY_ID = "extra_master_key_id"; + public static final String EXTRA_KEYSERVER = "extra_keyserver"; + + private final int REVOKE_OP_ID = 1; + private final int DELETE_OP_ID = 2; + private CryptoOperationHelper mRevokeOpHelper; + private CryptoOperationHelper mDeleteOpHelper; + + private long mMasterKeyId; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mRevokeOpHelper = new CryptoOperationHelper<>(this, + getRevocationCallback(), R.string.progress_revoking_uploading, REVOKE_OP_ID); + mRevokeOpHelper.onRestoreInstanceState(savedInstanceState); + + mDeleteOpHelper = new CryptoOperationHelper<>(this, + getDeletionCallback(), R.string.progress_deleting, DELETE_OP_ID); + mDeleteOpHelper.onRestoreInstanceState(savedInstanceState); + + mMasterKeyId = getIntent().getLongExtra(EXTRA_MASTER_KEY_ID, -1); + + RevokeDeleteDialogFragment fragment = RevokeDeleteDialogFragment.newInstance(); + fragment.show(getSupportFragmentManager(), "deleteRevokeDialog"); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + mDeleteOpHelper.handleActivityResult(requestCode, resultCode, data); + mRevokeOpHelper.handleActivityResult(requestCode, resultCode, data); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mRevokeOpHelper.onSaveInstanceState(outState); + mDeleteOpHelper.onSaveInstanceState(outState); + } + + private void returnResult(OperationResult result) { + Intent intent = new Intent(); + intent.putExtra(OperationResult.EXTRA_RESULT, result); + setResult(RESULT_OK, intent); + finish(); + } + + private CryptoOperationHelper.Callback getRevocationCallback() { + + CryptoOperationHelper.Callback callback + = new CryptoOperationHelper.Callback() { + @Override + public RevokeKeyringParcel createOperationInput() { + return new RevokeKeyringParcel(mMasterKeyId, true, + getIntent().getStringExtra(EXTRA_KEYSERVER)); + } + + @Override + public void onCryptoOperationSuccess(RevokeResult result) { + returnResult(result); + } + + @Override + public void onCryptoOperationCancelled() { + setResult(RESULT_CANCELED); + finish(); + } + + @Override + public void onCryptoOperationError(RevokeResult result) { + returnResult(result); + } + + @Override + public boolean onCryptoSetProgress(String msg, int progress, int max) { + return false; + } + }; + + return callback; + } + + private CryptoOperationHelper.Callback getDeletionCallback() { + + CryptoOperationHelper.Callback callback + = new CryptoOperationHelper.Callback() { + @Override + public DeleteKeyringParcel createOperationInput() { + return new DeleteKeyringParcel(new long[]{mMasterKeyId}, true); + } + + @Override + public void onCryptoOperationSuccess(DeleteResult result) { + returnResult(result); + } + + @Override + public void onCryptoOperationCancelled() { + setResult(RESULT_CANCELED); + finish(); + } + + @Override + public void onCryptoOperationError(DeleteResult result) { + returnResult(result); + } + + @Override + public boolean onCryptoSetProgress(String msg, int progress, int max) { + return false; + } + }; + + return callback; + } + + private void startRevocationOperation() { + mRevokeOpHelper.cryptoOperation(); + } + + private void startDeletionOperation() { + mDeleteOpHelper.cryptoOperation(); + } + + public static class RevokeDeleteDialogFragment extends DialogFragment { + + public static RevokeDeleteDialogFragment newInstance() { + RevokeDeleteDialogFragment frag = new RevokeDeleteDialogFragment(); + return frag; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Activity activity = getActivity(); + + final String CHOICE_REVOKE = getString(R.string.del_rev_dialog_choice_rev_upload); + final String CHOICE_DELETE = getString(R.string.del_rev_dialog_choice_delete); + + // if the dialog is displayed from the application class, design is missing + // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay + ContextThemeWrapper theme = new ContextThemeWrapper(activity, + R.style.Theme_AppCompat_Light_Dialog); + + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); + alert.setTitle(R.string.del_rev_dialog_title); + + LayoutInflater inflater = LayoutInflater.from(theme); + View view = inflater.inflate(R.layout.del_rev_dialog, null); + alert.setView(view); + + final Spinner spinner = (Spinner) view.findViewById(R.id.spinner); + + alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + activity.setResult(RESULT_CANCELED); + activity.finish(); + } + }); + + alert.setPositiveButton(R.string.del_rev_dialog_btn_revoke, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + String choice = spinner.getSelectedItem().toString(); + if (choice.equals(CHOICE_REVOKE)) { + ((RevokeDeleteDialogActivity) activity) + .startRevocationOperation(); + } else if (choice.equals(CHOICE_DELETE)) { + ((RevokeDeleteDialogActivity) activity) + .startDeletionOperation(); + } else { + throw new AssertionError( + "Unsupported delete type in RevokeDeleteDialogFragment"); + } + } + }); + + final AlertDialog alertDialog = alert.show(); + + spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + public void onItemSelected(AdapterView parent, View view, int pos, long id) { + + String choice = parent.getItemAtPosition(pos).toString(); + + if (choice.equals(CHOICE_REVOKE)) { + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) + .setText(R.string.del_rev_dialog_btn_revoke); + } else if (choice.equals(CHOICE_DELETE)) { + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) + .setText(R.string.del_rev_dialog_btn_delete); + } else { + throw new AssertionError( + "Unsupported delete type in RevokeDeleteDialogFragment"); + } + } + + public void onNothingSelected(AdapterView parent) { + } + }); + + return alertDialog; + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 9ed46d517..32b5c76b7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -68,7 +68,6 @@ import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus; import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; -import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; @@ -85,7 +84,6 @@ import org.sufficientlysecure.keychain.util.Preferences; import java.io.IOException; import java.util.ArrayList; - public class ViewKeyActivity extends BaseNfcActivity implements LoaderManager.LoaderCallbacks, CryptoOperationHelper.Callback { @@ -97,6 +95,8 @@ public class ViewKeyActivity extends BaseNfcActivity implements static final int REQUEST_QR_FINGERPRINT = 1; static final int REQUEST_BACKUP = 2; static final int REQUEST_CERTIFY = 3; + static final int REQUEST_DELETE = 4; + static final int REQUEST_REVOKE_DELETE = 5; public static final String EXTRA_DISPLAY_RESULT = "display_result"; @@ -419,27 +419,24 @@ public class ViewKeyActivity extends BaseNfcActivity implements } private void deleteKey() { - new Handler().post(new Runnable() { - @Override - public void run() { - // Message is received after key is deleted - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.arg1 == MessageStatus.OKAY.ordinal()) { - setResult(RESULT_CANCELED); - finish(); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, - new long[]{ mMasterKeyId }); - deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog"); - } - }); + if (mIsSecret && !mIsRevoked) { + Intent revokeDeleteIntent = new Intent(this, RevokeDeleteDialogActivity.class); + + revokeDeleteIntent.putExtra(RevokeDeleteDialogActivity.EXTRA_MASTER_KEY_ID, + mMasterKeyId); + revokeDeleteIntent.putExtra(RevokeDeleteDialogActivity.EXTRA_KEYSERVER, + Preferences.getPreferences(this).getPreferredKeyserver()); + + startActivityForResult(revokeDeleteIntent, REQUEST_REVOKE_DELETE); + + } else { + Intent deleteIntent = new Intent(this, DeleteKeyDialogActivity.class); + + deleteIntent.putExtra(DeleteKeyDialogActivity.EXTRA_DELETE_MASTER_KEY_IDS, + new long[]{mMasterKeyId}); + + startActivityForResult(deleteIntent, REQUEST_DELETE); + } } @Override @@ -487,6 +484,13 @@ public class ViewKeyActivity extends BaseNfcActivity implements } return; } + + case REQUEST_REVOKE_DELETE: + case REQUEST_DELETE: { + setResult(RESULT_OK, data); + finish(); + return; + } } super.onActivityResult(requestCode, resultCode, data); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java index 91ea969d7..c03c301a7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java @@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.NfcOperationActivity; import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity; import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; +import org.sufficientlysecure.keychain.ui.RevokeDeleteDialogActivity; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.util.Log; @@ -119,17 +120,13 @@ public class CryptoOperationHelper - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentActivity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.DeleteResult; -import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.DeleteKeyringParcel; -import org.sufficientlysecure.keychain.service.ServiceProgressHandler; -import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.HashMap; - -public class DeleteKeyDialogFragment extends DialogFragment - implements CryptoOperationHelper.Callback { - private static final String ARG_MESSENGER = "messenger"; - private static final String ARG_DELETE_MASTER_KEY_IDS = "delete_master_key_ids"; - - public static final int MESSAGE_OKAY = 1; - public static final int MESSAGE_ERROR = 0; - - private TextView mMainMessage; - private View mInflateView; - - private Messenger mMessenger; - - // for CryptoOperationHelper.Callback - private long[] mMasterKeyIds; - private boolean mHasSecret; - private CryptoOperationHelper mDeleteOpHelper; - - /** - * Creates new instance of this delete file dialog fragment - */ - public static DeleteKeyDialogFragment newInstance(Messenger messenger, long[] masterKeyIds) { - DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment(); - Bundle args = new Bundle(); - - args.putParcelable(ARG_MESSENGER, messenger); - args.putLongArray(ARG_DELETE_MASTER_KEY_IDS, masterKeyIds); - - frag.setArguments(args); - - return frag; - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (mDeleteOpHelper != null) { - mDeleteOpHelper.handleActivityResult(requestCode, resultCode, data); - } - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final FragmentActivity activity = getActivity(); - mMessenger = getArguments().getParcelable(ARG_MESSENGER); - - final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS); - - CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(activity); - - // Setup custom View to display in AlertDialog - LayoutInflater inflater = activity.getLayoutInflater(); - mInflateView = inflater.inflate(R.layout.view_key_delete_fragment, null); - builder.setView(mInflateView); - - mMainMessage = (TextView) mInflateView.findViewById(R.id.mainMessage); - - final boolean hasSecret; - - // If only a single key has been selected - if (masterKeyIds.length == 1) { - long masterKeyId = masterKeyIds[0]; - - try { - HashMap data = new ProviderHelper(activity).getUnifiedData( - masterKeyId, new String[]{ - KeyRings.USER_ID, - KeyRings.HAS_ANY_SECRET - }, new int[]{ - ProviderHelper.FIELD_TYPE_STRING, - ProviderHelper.FIELD_TYPE_INTEGER - } - ); - String name; - KeyRing.UserId mainUserId = KeyRing.splitUserId((String) data.get(KeyRings.USER_ID)); - if (mainUserId.name != null) { - name = mainUserId.name; - } else { - name = getString(R.string.user_id_no_name); - } - hasSecret = ((Long) data.get(KeyRings.HAS_ANY_SECRET)) == 1; - - if (hasSecret) { - // show title only for secret key deletions, - // see http://www.google.com/design/spec/components/dialogs.html#dialogs-behavior - builder.setTitle(getString(R.string.title_delete_secret_key, name)); - mMainMessage.setText(getString(R.string.secret_key_deletion_confirmation, name)); - } else { - mMainMessage.setText(getString(R.string.public_key_deletetion_confirmation, name)); - } - } catch (ProviderHelper.NotFoundException e) { - dismiss(); - return null; - } - } else { - mMainMessage.setText(R.string.key_deletion_confirmation_multi); - hasSecret = false; - } - - builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - - mMasterKeyIds = masterKeyIds; - mHasSecret = hasSecret; - - mDeleteOpHelper = new CryptoOperationHelper<> - (1, DeleteKeyDialogFragment.this, DeleteKeyDialogFragment.this, - R.string.progress_deleting); - mDeleteOpHelper.cryptoOperation(); - // do NOT dismiss here, it'll give - // OperationHelper a null fragmentManager - // dismiss(); - } - }); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - } - }); - - return builder.show(); - } - - @Override - public DeleteKeyringParcel createOperationInput() { - return new DeleteKeyringParcel(mMasterKeyIds, mHasSecret); - } - - @Override - public void onCryptoOperationSuccess(DeleteResult result) { - handleResult(result); - } - - @Override - public void onCryptoOperationCancelled() { - - } - - @Override - public void onCryptoOperationError(DeleteResult result) { - handleResult(result); - } - - @Override - public boolean onCryptoSetProgress(String msg, int progress, int max) { - return false; - } - - public void handleResult(DeleteResult result) { - try { - Bundle data = new Bundle(); - data.putParcelable(OperationResult.EXTRA_RESULT, result); - Message msg = Message.obtain(); - msg.arg1 = ServiceProgressHandler.MessageStatus.OKAY.ordinal(); - msg.setData(data); - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "messenger error", e); - } - dismiss(); - } -} diff --git a/OpenKeychain/src/main/res/layout/del_rev_dialog.xml b/OpenKeychain/src/main/res/layout/del_rev_dialog.xml new file mode 100644 index 000000000..bcf9948db --- /dev/null +++ b/OpenKeychain/src/main/res/layout/del_rev_dialog.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/values/arrays.xml b/OpenKeychain/src/main/res/values/arrays.xml index 241f530d8..a9f521b17 100644 --- a/OpenKeychain/src/main/res/values/arrays.xml +++ b/OpenKeychain/src/main/res/values/arrays.xml @@ -37,6 +37,10 @@ @string/pref_proxy_type_value_http @string/pref_proxy_type_value_socks + + @string/del_rev_dialog_choice_rev_upload + @string/del_rev_dialog_choice_delete + @string/key_size_2048 @string/key_size_4096 diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 84d6716be..1c9b22fb2 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -361,6 +361,7 @@ "cancelling…" "saving…" "importing…" + "Revoking and uploading key…" "Updating keys…" "exporting…" "uploading…" @@ -524,6 +525,12 @@ "Nothing to delete." "Delete operation cancelled." + + "Successfully revoked key." + "Error revoking key!" + "Nothing to revoke." + "Revoke operation cancelled." + "Successfully certified key%2$s." @@ -584,6 +591,17 @@ "Share with QR Code" "Share with NFC" + + "If you would no longer like to use this key, it should be revoked and uploaded. Select delete only if you wish to remove the key from OpenKeychain but continue to use it from somewhere else." + "Revoke/Delete key" + "Revoke and upload" + "Delete only" + + + "Delete only" + "Revoke and Upload" + + "1 key selected." @@ -1270,6 +1288,13 @@ "Failed to delete %d keys" + "Nothing to revoke!" + "Secret keys can only be revoked individually!" + "Cannot find key to revoke!" + "Revoking key %s" + "Failed revoking key" + "Successfully revoked key" + "Account saved" "Downloaded successfully!" -- cgit v1.2.3 From d1409fd5c89bc10dd0c39a228049e4c2f669c65a Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Fri, 10 Jul 2015 00:26:48 +0530 Subject: use only one DeleteDialogActivity --- OpenKeychain/src/main/AndroidManifest.xml | 3 - .../operations/results/OperationResult.java | 2 +- .../keychain/ui/DeleteKeyDialogActivity.java | 279 ++++++++++++++++----- .../keychain/ui/KeyListFragment.java | 9 +- .../keychain/ui/RevokeDeleteDialogActivity.java | 258 ------------------- .../keychain/ui/ViewKeyActivity.java | 28 +-- .../keychain/ui/base/CryptoOperationHelper.java | 11 +- .../src/main/res/layout/del_rev_dialog.xml | 5 +- 8 files changed, 244 insertions(+), 351 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RevokeDeleteDialogActivity.java (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index 7e4f13db5..c5b1d1a3d 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -685,9 +685,6 @@ - diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 5105b7fdc..c65412a1f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -764,7 +764,7 @@ public abstract class OperationResult implements Parcelable { MSG_REVOKE_ERROR_MULTI_SECRET (LogLevel.DEBUG, R.string.msg_revoke_error_multi_secret), MSG_REVOKE_ERROR_NOT_FOUND (LogLevel.DEBUG, R.string.msg_revoke_error_multi_secret), MSG_REVOKE (LogLevel.DEBUG, R.string.msg_revoke_key), - MSG_REVOKE_KEY_FAIL (LogLevel.WARN, R.string.msg_revoke_key_fail), + MSG_REVOKE_KEY_FAIL (LogLevel.ERROR, R.string.msg_revoke_key_fail), MSG_REVOKE_OK (LogLevel.OK, R.string.msg_revoke_ok), // keybase verification diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java index 064d34e38..b89c476d6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -1,5 +1,7 @@ package org.sufficientlysecure.keychain.ui; +import android.app.Activity; +import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; @@ -8,32 +10,40 @@ import android.os.Handler; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; +import android.widget.AdapterView; +import android.widget.Spinner; import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.DeleteResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.operations.results.RevokeResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.DeleteKeyringParcel; +import org.sufficientlysecure.keychain.service.RevokeKeyringParcel; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; import org.sufficientlysecure.keychain.util.Log; import java.util.HashMap; -public class DeleteKeyDialogActivity extends FragmentActivity - implements CryptoOperationHelper.Callback { +public class DeleteKeyDialogActivity extends FragmentActivity { public static final String EXTRA_DELETE_MASTER_KEY_IDS = "extra_delete_master_key_ids"; + public static final String EXTRA_HAS_SECRET = "extra_has_secret"; + public static final String EXTRA_KEYSERVER = "extra_keyserver"; private CryptoOperationHelper mDeleteOpHelper; + private CryptoOperationHelper mRevokeOpHelper; private long[] mMasterKeyIds; private boolean mHasSecret; @@ -42,95 +52,168 @@ public class DeleteKeyDialogActivity extends FragmentActivity protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mDeleteOpHelper = new CryptoOperationHelper<>(DeleteKeyDialogActivity.this, - DeleteKeyDialogActivity.this, R.string.progress_deleting); - mDeleteOpHelper.onRestoreInstanceState(savedInstanceState); + mDeleteOpHelper = new CryptoOperationHelper<>(1, DeleteKeyDialogActivity.this, + getDeletionCallback(), R.string.progress_deleting); + + mRevokeOpHelper = new CryptoOperationHelper<>(2, this, + getRevocationCallback(), R.string.progress_revoking_uploading); mMasterKeyIds = getIntent().getLongArrayExtra(EXTRA_DELETE_MASTER_KEY_IDS); + mHasSecret = getIntent().getBooleanExtra(EXTRA_HAS_SECRET, false); - Handler deleteDialogHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - if (msg.what == DeleteKeyDialogFragment.MESSAGE_PERFORM_DELETE) { - mHasSecret = msg.getData().getBoolean(DeleteKeyDialogFragment.MSG_HAS_SECRET); - mDeleteOpHelper.cryptoOperation(); + if (mMasterKeyIds.length > 1 && mHasSecret) { + throw new AssertionError("Secret keys can be deleted only one at a time!" + + " Should be checked before reaching DeleteKeyDialogActivity."); + } + + if (mMasterKeyIds.length == 1 && mHasSecret) { + // if mMasterKeyIds.length == 0 we let the DeleteOperation respond + try { + HashMap data = new ProviderHelper(this).getUnifiedData( + mMasterKeyIds[0], new String[]{ + KeychainContract.KeyRings.USER_ID, + KeychainContract.KeyRings.IS_REVOKED + }, new int[]{ + ProviderHelper.FIELD_TYPE_STRING, + ProviderHelper.FIELD_TYPE_INTEGER + } + ); + if ((long) data.get(KeychainContract.KeyRings.IS_REVOKED) > 0) { + showNormalDeleteDialog(); + } else { + showRevokeDeleteDialog(); } + } catch (ProviderHelper.NotFoundException e) { + Log.e(Constants.TAG, + "Secret key to delete not found at DeleteKeyDialogActivity for " + + mMasterKeyIds[0], e); + finish(); + return; } - }; + } else { + showNormalDeleteDialog(); + } + } - Messenger messenger = new Messenger(deleteDialogHandler); + private void showNormalDeleteDialog() { DeleteKeyDialogFragment deleteKeyDialogFragment - = DeleteKeyDialogFragment.newInstance(messenger, mMasterKeyIds); + = DeleteKeyDialogFragment.newInstance(mMasterKeyIds); deleteKeyDialogFragment.show(getSupportFragmentManager(), "deleteKeyDialog"); - } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - mDeleteOpHelper.handleActivityResult(requestCode, resultCode, data); } - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mDeleteOpHelper.onSaveInstanceState(outState); - } + private void showRevokeDeleteDialog() { - @Override - public DeleteKeyringParcel createOperationInput() { - return new DeleteKeyringParcel(mMasterKeyIds, mHasSecret); + RevokeDeleteDialogFragment fragment = RevokeDeleteDialogFragment.newInstance(); + fragment.show(getSupportFragmentManager(), "deleteRevokeDialog"); } - @Override - public void onCryptoOperationSuccess(DeleteResult result) { - handleResult(result); + private void startRevocationOperation() { + mRevokeOpHelper.cryptoOperation(); } - @Override - public void onCryptoOperationCancelled() { - setResult(RESULT_CANCELED); - finish(); + private void startDeletionOperation() { + mDeleteOpHelper.cryptoOperation(); } - @Override - public void onCryptoOperationError(DeleteResult result) { - handleResult(result); + private CryptoOperationHelper.Callback getRevocationCallback() { + + CryptoOperationHelper.Callback callback + = new CryptoOperationHelper.Callback() { + @Override + public RevokeKeyringParcel createOperationInput() { + return new RevokeKeyringParcel(mMasterKeyIds[0], true, + getIntent().getStringExtra(EXTRA_KEYSERVER)); + } + + @Override + public void onCryptoOperationSuccess(RevokeResult result) { + returnResult(result); + } + + @Override + public void onCryptoOperationCancelled() { + setResult(RESULT_CANCELED); + finish(); + } + + @Override + public void onCryptoOperationError(RevokeResult result) { + returnResult(result); + } + + @Override + public boolean onCryptoSetProgress(String msg, int progress, int max) { + return false; + } + }; + + return callback; } - @Override - public boolean onCryptoSetProgress(String msg, int progress, int max) { - return false; + private CryptoOperationHelper.Callback getDeletionCallback() { + + CryptoOperationHelper.Callback callback + = new CryptoOperationHelper.Callback() { + @Override + public DeleteKeyringParcel createOperationInput() { + return new DeleteKeyringParcel(mMasterKeyIds, true); + } + + @Override + public void onCryptoOperationSuccess(DeleteResult result) { + returnResult(result); + } + + @Override + public void onCryptoOperationCancelled() { + setResult(RESULT_CANCELED); + finish(); + } + + @Override + public void onCryptoOperationError(DeleteResult result) { + returnResult(result); + } + + @Override + public boolean onCryptoSetProgress(String msg, int progress, int max) { + return false; + } + }; + + return callback; } - public void handleResult(DeleteResult result) { + private void returnResult(OperationResult result) { Intent intent = new Intent(); intent.putExtra(OperationResult.EXTRA_RESULT, result); setResult(RESULT_OK, intent); finish(); } - public static class DeleteKeyDialogFragment extends DialogFragment { + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + mDeleteOpHelper.handleActivityResult(requestCode, resultCode, data); + mRevokeOpHelper.handleActivityResult(requestCode, resultCode, data); + } - public static final String MSG_HAS_SECRET = "msg_has_secret"; + public static class DeleteKeyDialogFragment extends DialogFragment { - private static final String ARG_MESSENGER = "messenger"; private static final String ARG_DELETE_MASTER_KEY_IDS = "delete_master_key_ids"; - public static final int MESSAGE_PERFORM_DELETE = 1; - private TextView mMainMessage; private View mInflateView; - private Messenger mMessenger; /** * Creates new instance of this delete file dialog fragment */ - public static DeleteKeyDialogFragment newInstance(Messenger messenger, long[] masterKeyIds) { + public static DeleteKeyDialogFragment newInstance(long[] masterKeyIds) { DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment(); Bundle args = new Bundle(); - args.putParcelable(ARG_MESSENGER, messenger); args.putLongArray(ARG_DELETE_MASTER_KEY_IDS, masterKeyIds); frag.setArguments(args); @@ -138,10 +221,10 @@ public class DeleteKeyDialogActivity extends FragmentActivity return frag; } + @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final FragmentActivity activity = getActivity(); - mMessenger = getArguments().getParcelable(ARG_MESSENGER); final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS); @@ -151,7 +234,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(theme); // Setup custom View to display in AlertDialog - LayoutInflater inflater = activity.getLayoutInflater(); + LayoutInflater inflater = LayoutInflater.from(theme); mInflateView = inflater.inflate(R.layout.view_key_delete_fragment, null); builder.setView(mInflateView); @@ -196,23 +279,13 @@ public class DeleteKeyDialogActivity extends FragmentActivity } } else { mMainMessage.setText(R.string.key_deletion_confirmation_multi); - hasSecret = false; } builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - Bundle data = new Bundle(); - data.putBoolean(MSG_HAS_SECRET, hasSecret); - Message msg = Message.obtain(); - msg.setData(data); - msg.what = MESSAGE_PERFORM_DELETE; - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "messenger error", e); - } + ((DeleteKeyDialogActivity) getActivity()).startDeletionOperation(); } }); @@ -228,4 +301,88 @@ public class DeleteKeyDialogActivity extends FragmentActivity } } + public static class RevokeDeleteDialogFragment extends DialogFragment { + + public static RevokeDeleteDialogFragment newInstance() { + RevokeDeleteDialogFragment frag = new RevokeDeleteDialogFragment(); + return frag; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Activity activity = getActivity(); + + final String CHOICE_REVOKE = getString(R.string.del_rev_dialog_choice_rev_upload); + final String CHOICE_DELETE = getString(R.string.del_rev_dialog_choice_delete); + + // if the dialog is displayed from the application class, design is missing + // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay + ContextThemeWrapper theme = new ContextThemeWrapper(activity, + R.style.Theme_AppCompat_Light_Dialog); + + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); + alert.setTitle(R.string.del_rev_dialog_title); + + LayoutInflater inflater = LayoutInflater.from(theme); + View view = inflater.inflate(R.layout.del_rev_dialog, null); + alert.setView(view); + + final Spinner spinner = (Spinner) view.findViewById(R.id.spinner); + + alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + activity.setResult(RESULT_CANCELED); + activity.finish(); + } + }); + + alert.setPositiveButton(R.string.del_rev_dialog_btn_revoke, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + String choice = spinner.getSelectedItem().toString(); + if (choice.equals(CHOICE_REVOKE)) { + ((DeleteKeyDialogActivity) activity) + .startRevocationOperation(); + } else if (choice.equals(CHOICE_DELETE)) { + ((DeleteKeyDialogActivity) activity) + .startDeletionOperation(); + } else { + throw new AssertionError( + "Unsupported delete type in RevokeDeleteDialogFragment"); + } + } + }); + + final AlertDialog alertDialog = alert.show(); + + spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + public void onItemSelected(AdapterView parent, View view, int pos, long id) { + + String choice = parent.getItemAtPosition(pos).toString(); + + if (choice.equals(CHOICE_REVOKE)) { + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) + .setText(R.string.del_rev_dialog_btn_revoke); + } else if (choice.equals(CHOICE_DELETE)) { + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) + .setText(R.string.del_rev_dialog_btn_delete); + } else { + throw new AssertionError( + "Unsupported delete type in RevokeDeleteDialogFragment"); + } + } + + public void onNothingSelected(AdapterView parent) { + } + }); + + return alertDialog; + } + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index c53220d69..b89b9d6ee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -366,6 +366,11 @@ public class KeyListFragment extends LoaderFragment Intent intent = new Intent(getActivity(), DeleteKeyDialogActivity.class); intent.putExtra(DeleteKeyDialogActivity.EXTRA_DELETE_MASTER_KEY_IDS, masterKeyIds); + intent.putExtra(DeleteKeyDialogActivity.EXTRA_HAS_SECRET, hasSecret); + if (hasSecret) { + intent.putExtra(DeleteKeyDialogActivity.EXTRA_KEYSERVER, + Preferences.getPreferences(getActivity()).getPreferredKeyserver()); + } startActivityForResult(intent, REQUEST_DELETE); } @@ -603,7 +608,9 @@ public class KeyListFragment extends LoaderFragment switch (requestCode) { case REQUEST_DELETE: - mActionMode.finish(); + if (mActionMode != null) { + mActionMode.finish(); + } if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); result.createNotify(getActivity()).show(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RevokeDeleteDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RevokeDeleteDialogActivity.java deleted file mode 100644 index b60003419..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RevokeDeleteDialogActivity.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * Copyright (C) 2015 Adithya Abraham Philip - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentActivity; -import android.view.ContextThemeWrapper; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.AdapterView; -import android.widget.Spinner; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.DeleteResult; -import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.operations.results.RevokeResult; -import org.sufficientlysecure.keychain.service.DeleteKeyringParcel; -import org.sufficientlysecure.keychain.service.RevokeKeyringParcel; -import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; -import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Preferences; - -public class RevokeDeleteDialogActivity extends FragmentActivity { - - public static final String EXTRA_MASTER_KEY_ID = "extra_master_key_id"; - public static final String EXTRA_KEYSERVER = "extra_keyserver"; - - private final int REVOKE_OP_ID = 1; - private final int DELETE_OP_ID = 2; - private CryptoOperationHelper mRevokeOpHelper; - private CryptoOperationHelper mDeleteOpHelper; - - private long mMasterKeyId; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mRevokeOpHelper = new CryptoOperationHelper<>(this, - getRevocationCallback(), R.string.progress_revoking_uploading, REVOKE_OP_ID); - mRevokeOpHelper.onRestoreInstanceState(savedInstanceState); - - mDeleteOpHelper = new CryptoOperationHelper<>(this, - getDeletionCallback(), R.string.progress_deleting, DELETE_OP_ID); - mDeleteOpHelper.onRestoreInstanceState(savedInstanceState); - - mMasterKeyId = getIntent().getLongExtra(EXTRA_MASTER_KEY_ID, -1); - - RevokeDeleteDialogFragment fragment = RevokeDeleteDialogFragment.newInstance(); - fragment.show(getSupportFragmentManager(), "deleteRevokeDialog"); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - mDeleteOpHelper.handleActivityResult(requestCode, resultCode, data); - mRevokeOpHelper.handleActivityResult(requestCode, resultCode, data); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mRevokeOpHelper.onSaveInstanceState(outState); - mDeleteOpHelper.onSaveInstanceState(outState); - } - - private void returnResult(OperationResult result) { - Intent intent = new Intent(); - intent.putExtra(OperationResult.EXTRA_RESULT, result); - setResult(RESULT_OK, intent); - finish(); - } - - private CryptoOperationHelper.Callback getRevocationCallback() { - - CryptoOperationHelper.Callback callback - = new CryptoOperationHelper.Callback() { - @Override - public RevokeKeyringParcel createOperationInput() { - return new RevokeKeyringParcel(mMasterKeyId, true, - getIntent().getStringExtra(EXTRA_KEYSERVER)); - } - - @Override - public void onCryptoOperationSuccess(RevokeResult result) { - returnResult(result); - } - - @Override - public void onCryptoOperationCancelled() { - setResult(RESULT_CANCELED); - finish(); - } - - @Override - public void onCryptoOperationError(RevokeResult result) { - returnResult(result); - } - - @Override - public boolean onCryptoSetProgress(String msg, int progress, int max) { - return false; - } - }; - - return callback; - } - - private CryptoOperationHelper.Callback getDeletionCallback() { - - CryptoOperationHelper.Callback callback - = new CryptoOperationHelper.Callback() { - @Override - public DeleteKeyringParcel createOperationInput() { - return new DeleteKeyringParcel(new long[]{mMasterKeyId}, true); - } - - @Override - public void onCryptoOperationSuccess(DeleteResult result) { - returnResult(result); - } - - @Override - public void onCryptoOperationCancelled() { - setResult(RESULT_CANCELED); - finish(); - } - - @Override - public void onCryptoOperationError(DeleteResult result) { - returnResult(result); - } - - @Override - public boolean onCryptoSetProgress(String msg, int progress, int max) { - return false; - } - }; - - return callback; - } - - private void startRevocationOperation() { - mRevokeOpHelper.cryptoOperation(); - } - - private void startDeletionOperation() { - mDeleteOpHelper.cryptoOperation(); - } - - public static class RevokeDeleteDialogFragment extends DialogFragment { - - public static RevokeDeleteDialogFragment newInstance() { - RevokeDeleteDialogFragment frag = new RevokeDeleteDialogFragment(); - return frag; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Activity activity = getActivity(); - - final String CHOICE_REVOKE = getString(R.string.del_rev_dialog_choice_rev_upload); - final String CHOICE_DELETE = getString(R.string.del_rev_dialog_choice_delete); - - // if the dialog is displayed from the application class, design is missing - // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay - ContextThemeWrapper theme = new ContextThemeWrapper(activity, - R.style.Theme_AppCompat_Light_Dialog); - - CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); - alert.setTitle(R.string.del_rev_dialog_title); - - LayoutInflater inflater = LayoutInflater.from(theme); - View view = inflater.inflate(R.layout.del_rev_dialog, null); - alert.setView(view); - - final Spinner spinner = (Spinner) view.findViewById(R.id.spinner); - - alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - activity.setResult(RESULT_CANCELED); - activity.finish(); - } - }); - - alert.setPositiveButton(R.string.del_rev_dialog_btn_revoke, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - - String choice = spinner.getSelectedItem().toString(); - if (choice.equals(CHOICE_REVOKE)) { - ((RevokeDeleteDialogActivity) activity) - .startRevocationOperation(); - } else if (choice.equals(CHOICE_DELETE)) { - ((RevokeDeleteDialogActivity) activity) - .startDeletionOperation(); - } else { - throw new AssertionError( - "Unsupported delete type in RevokeDeleteDialogFragment"); - } - } - }); - - final AlertDialog alertDialog = alert.show(); - - spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - public void onItemSelected(AdapterView parent, View view, int pos, long id) { - - String choice = parent.getItemAtPosition(pos).toString(); - - if (choice.equals(CHOICE_REVOKE)) { - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) - .setText(R.string.del_rev_dialog_btn_revoke); - } else if (choice.equals(CHOICE_DELETE)) { - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) - .setText(R.string.del_rev_dialog_btn_delete); - } else { - throw new AssertionError( - "Unsupported delete type in RevokeDeleteDialogFragment"); - } - } - - public void onNothingSelected(AdapterView parent) { - } - }); - - return alertDialog; - } - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 32b5c76b7..08ef38746 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -96,7 +96,6 @@ public class ViewKeyActivity extends BaseNfcActivity implements static final int REQUEST_BACKUP = 2; static final int REQUEST_CERTIFY = 3; static final int REQUEST_DELETE = 4; - static final int REQUEST_REVOKE_DELETE = 5; public static final String EXTRA_DISPLAY_RESULT = "display_result"; @@ -419,24 +418,18 @@ public class ViewKeyActivity extends BaseNfcActivity implements } private void deleteKey() { - if (mIsSecret && !mIsRevoked) { - Intent revokeDeleteIntent = new Intent(this, RevokeDeleteDialogActivity.class); - - revokeDeleteIntent.putExtra(RevokeDeleteDialogActivity.EXTRA_MASTER_KEY_ID, - mMasterKeyId); - revokeDeleteIntent.putExtra(RevokeDeleteDialogActivity.EXTRA_KEYSERVER, + Intent deleteIntent = new Intent(this, DeleteKeyDialogActivity.class); + + deleteIntent.putExtra(DeleteKeyDialogActivity.EXTRA_DELETE_MASTER_KEY_IDS, + new long[]{mMasterKeyId}); + deleteIntent.putExtra(DeleteKeyDialogActivity.EXTRA_HAS_SECRET, mIsSecret); + if (mIsSecret) { + // for upload in case key is secret + deleteIntent.putExtra(DeleteKeyDialogActivity.EXTRA_KEYSERVER, Preferences.getPreferences(this).getPreferredKeyserver()); - - startActivityForResult(revokeDeleteIntent, REQUEST_REVOKE_DELETE); - - } else { - Intent deleteIntent = new Intent(this, DeleteKeyDialogActivity.class); - - deleteIntent.putExtra(DeleteKeyDialogActivity.EXTRA_DELETE_MASTER_KEY_IDS, - new long[]{mMasterKeyId}); - - startActivityForResult(deleteIntent, REQUEST_DELETE); } + + startActivityForResult(deleteIntent, REQUEST_DELETE); } @Override @@ -485,7 +478,6 @@ public class ViewKeyActivity extends BaseNfcActivity implements return; } - case REQUEST_REVOKE_DELETE: case REQUEST_DELETE: { setResult(RESULT_OK, data); finish(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java index c03c301a7..4cb3d5841 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java @@ -40,7 +40,6 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.NfcOperationActivity; import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity; import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; -import org.sufficientlysecure.keychain.ui.RevokeDeleteDialogActivity; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.util.Log; @@ -152,13 +151,11 @@ public class CryptoOperationHelper + android:textAppearance="@style/TextAppearance.AppCompat.Medium" + android:layout_marginBottom="16dp"/> + android:textAppearance="?android:textAppearanceLarge"/> \ No newline at end of file -- cgit v1.2.3 From faa66d6140e7f68d920e612c21fa01139b12170e Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Fri, 10 Jul 2015 02:02:27 +0530 Subject: prevented passphrase caching on revocation --- .../keychain/operations/EditKeyOperation.java | 2 +- .../keychain/operations/RevokeOperation.java | 3 ++ .../keychain/service/input/CryptoInputParcel.java | 17 +++++++- .../keychain/ui/DeleteKeyDialogActivity.java | 3 +- .../keychain/ui/PassphraseDialogActivity.java | 48 ++++++++++++++++------ .../keychain/ui/base/CryptoOperationHelper.java | 3 +- 6 files changed, 59 insertions(+), 17 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java index f8f7e79a3..6a1c01dd1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -161,7 +161,7 @@ public class EditKeyOperation extends BaseOperation { } // There is a new passphrase - cache it - if (saveParcel.mNewUnlock != null) { + if (saveParcel.mNewUnlock != null && cryptoInput.mCachePassphrase) { log.add(LogType.MSG_ED_CACHING_NEW, 1); // NOTE: Don't cache empty passphrases! Important for MOVE_KEY_TO_CARD diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java index 157e36e04..0fc3f1bc3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java @@ -32,6 +32,9 @@ public class RevokeOperation extends BaseOperation { public OperationResult execute(RevokeKeyringParcel revokeKeyringParcel, CryptoInputParcel cryptoInputParcel) { + // we don't cache passphrases during revocation + cryptoInputParcel.mCachePassphrase = false; + long masterKeyId = revokeKeyringParcel.mMasterKeyId; OperationResult.OperationLog log = new OperationResult.OperationLog(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java index d4cebe67c..9ba9601e5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java @@ -34,12 +34,15 @@ import java.util.Map; public class CryptoInputParcel implements Parcelable { final Date mSignatureTime; - final Passphrase mPassphrase; + public Passphrase mPassphrase; // used to supply an explicit proxy to operations that require it // this is not final so it can be added to an existing CryptoInputParcel // (e.g) CertifyOperation with upload might require both passphrase and orbot to be enabled private ParcelableProxy mParcelableProxy; + // specifies whether passphrases should be cached + public boolean mCachePassphrase = true; + // this map contains both decrypted session keys and signed hashes to be // used in the crypto operation described by this parcel. private HashMap mCryptoData = new HashMap<>(); @@ -47,21 +50,25 @@ public class CryptoInputParcel implements Parcelable { public CryptoInputParcel() { mSignatureTime = new Date(); mPassphrase = null; + mCachePassphrase = true; } public CryptoInputParcel(Date signatureTime, Passphrase passphrase) { mSignatureTime = signatureTime == null ? new Date() : signatureTime; mPassphrase = passphrase; + mCachePassphrase = true; } public CryptoInputParcel(Passphrase passphrase) { mSignatureTime = new Date(); mPassphrase = passphrase; + mCachePassphrase = true; } public CryptoInputParcel(Date signatureTime) { mSignatureTime = signatureTime == null ? new Date() : signatureTime; mPassphrase = null; + mCachePassphrase = true; } public CryptoInputParcel(ParcelableProxy parcelableProxy) { @@ -69,10 +76,17 @@ public class CryptoInputParcel implements Parcelable { mParcelableProxy = parcelableProxy; } + public CryptoInputParcel(boolean cachePassphrase) { + mSignatureTime = new Date(); + mPassphrase = null; + mCachePassphrase = cachePassphrase; + } + protected CryptoInputParcel(Parcel source) { mSignatureTime = new Date(source.readLong()); mPassphrase = source.readParcelable(getClass().getClassLoader()); mParcelableProxy = source.readParcelable(getClass().getClassLoader()); + mCachePassphrase = source.readByte() != 0; { int count = source.readInt(); @@ -96,6 +110,7 @@ public class CryptoInputParcel implements Parcelable { dest.writeLong(mSignatureTime.getTime()); dest.writeParcelable(mPassphrase, 0); dest.writeParcelable(mParcelableProxy, 0); + dest.writeByte((byte) (mCachePassphrase ? 1 : 0)); dest.writeInt(mCryptoData.size()); for (HashMap.Entry entry : mCryptoData.entrySet()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java index b89c476d6..98d3cf7b0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -31,6 +31,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.DeleteKeyringParcel; import org.sufficientlysecure.keychain.service.RevokeKeyringParcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; import org.sufficientlysecure.keychain.util.Log; @@ -111,7 +112,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { } private void startRevocationOperation() { - mRevokeOpHelper.cryptoOperation(); + mRevokeOpHelper.cryptoOperation(new CryptoInputParcel(false)); } private void startDeletionOperation() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index 004d1d127..c9f6423d6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -72,11 +72,14 @@ public class PassphraseDialogActivity extends FragmentActivity { public static final String EXTRA_REQUIRED_INPUT = "required_input"; public static final String EXTRA_SUBKEY_ID = "secret_key_id"; + public static final String EXTRA_CRYPTO_INPUT = "crypto_input"; // special extra for OpenPgpService public static final String EXTRA_SERVICE_INTENT = "data"; private long mSubKeyId; + private CryptoInputParcel mCryptoInputParcel; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -90,6 +93,8 @@ public class PassphraseDialogActivity extends FragmentActivity { ); } + mCryptoInputParcel = getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT); + // this activity itself has no content view (see manifest) if (getIntent().hasExtra(EXTRA_SUBKEY_ID)) { @@ -330,11 +335,16 @@ public class PassphraseDialogActivity extends FragmentActivity { public void onClick(View v) { final Passphrase passphrase = new Passphrase(mPassphraseEditText); + CryptoInputParcel cryptoInputParcel = + ((PassphraseDialogActivity) getActivity()).mCryptoInputParcel; + // Early breakout if we are dealing with a symmetric key if (mSecretRing == null) { - PassphraseCacheService.addCachedPassphrase(getActivity(), - Constants.key.symmetric, Constants.key.symmetric, passphrase, - getString(R.string.passp_cache_notif_pwd)); + if (cryptoInputParcel.mCachePassphrase) { + PassphraseCacheService.addCachedPassphrase(getActivity(), + Constants.key.symmetric, Constants.key.symmetric, passphrase, + getString(R.string.passp_cache_notif_pwd)); + } finishCaching(passphrase); return; @@ -387,15 +397,24 @@ public class PassphraseDialogActivity extends FragmentActivity { return; } - // cache the new passphrase - Log.d(Constants.TAG, "Everything okay! Caching entered passphrase"); + // cache the new passphrase as specified in CryptoInputParcel + Log.d(Constants.TAG, "Everything okay!"); - try { - PassphraseCacheService.addCachedPassphrase(getActivity(), - mSecretRing.getMasterKeyId(), mSubKeyId, passphrase, - mSecretRing.getPrimaryUserIdWithFallback()); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "adding of a passphrase failed", e); + CryptoInputParcel cryptoInputParcel + = ((PassphraseDialogActivity) getActivity()).mCryptoInputParcel; + + if (cryptoInputParcel.mCachePassphrase) { + Log.d(Constants.TAG, "Caching entered passphrase"); + + try { + PassphraseCacheService.addCachedPassphrase(getActivity(), + mSecretRing.getMasterKeyId(), mSubKeyId, passphrase, + mSecretRing.getPrimaryUserIdWithFallback()); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "adding of a passphrase failed", e); + } + } else { + Log.d(Constants.TAG, "Not caching entered passphrase!"); } finishCaching(passphrase); @@ -411,9 +430,12 @@ public class PassphraseDialogActivity extends FragmentActivity { return; } - CryptoInputParcel inputParcel = new CryptoInputParcel(null, passphrase); + CryptoInputParcel inputParcel = + ((PassphraseDialogActivity) getActivity()).mCryptoInputParcel; + inputParcel.mPassphrase = passphrase; if (mServiceIntent != null) { - CryptoInputParcelCacheService.addCryptoInputParcel(getActivity(), mServiceIntent, inputParcel); + CryptoInputParcelCacheService.addCryptoInputParcel(getActivity(), mServiceIntent, + inputParcel); getActivity().setResult(RESULT_OK, mServiceIntent); } else { // also return passphrase back to activity diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java index 4cb3d5841..398b3e778 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java @@ -118,7 +118,7 @@ public class CryptoOperationHelper Date: Fri, 10 Jul 2015 02:31:17 +0530 Subject: allowed operations to modify CryptoInputParcel they receive --- .../keychain/operations/CertifyOperation.java | 9 ++++++--- .../keychain/operations/ExportOperation.java | 14 +------------- .../keychain/operations/ImportOperation.java | 2 +- .../keychain/operations/KeybaseVerificationOperation.java | 2 +- .../keychain/operations/SignEncryptOperation.java | 4 ++-- .../keychain/operations/results/CertifyResult.java | 6 ++++-- .../keychain/operations/results/DecryptVerifyResult.java | 5 +++-- .../keychain/operations/results/DeleteResult.java | 6 ++++-- .../keychain/operations/results/ExportResult.java | 6 ++++-- .../keychain/operations/results/GetKeyResult.java | 6 ++++-- .../keychain/operations/results/ImportKeyResult.java | 5 +++-- .../keychain/operations/results/InputPendingResult.java | 2 +- .../operations/results/KeybaseVerificationResult.java | 6 ++++-- .../keychain/operations/results/PgpEditKeyResult.java | 6 ++++-- .../keychain/operations/results/PgpSignEncryptResult.java | 6 ++++-- .../keychain/operations/results/RevokeResult.java | 6 ++++-- .../keychain/operations/results/SignEncryptResult.java | 7 +++++-- .../sufficientlysecure/keychain/pgp/PgpDecryptVerify.java | 11 +++++++---- .../sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 6 +++--- .../keychain/pgp/PgpSignEncryptOperation.java | 4 ++-- .../keychain/ui/adapter/ImportKeysListCloudLoader.java | 4 +++- .../keychain/ui/base/CryptoOperationHelper.java | 7 +++---- 22 files changed, 73 insertions(+), 57 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java index d0377cc24..eeed24db0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java @@ -103,7 +103,10 @@ public class CertifyOperation extends BaseOperation { if (passphrase == null) { return new CertifyResult(log, RequiredInputParcel.createRequiredSignPassphrase( - certificationKey.getKeyId(), certificationKey.getKeyId(), null) + certificationKey.getKeyId(), + certificationKey.getKeyId(), + null), + cryptoInput ); } break; @@ -189,7 +192,7 @@ public class CertifyOperation extends BaseOperation { if (!allRequiredInput.isEmpty()) { log.add(LogType.MSG_CRT_NFC_RETURN, 1); - return new CertifyResult(log, allRequiredInput.build()); + return new CertifyResult(log, allRequiredInput.build(), cryptoInput); } log.add(LogType.MSG_CRT_SAVING, 1); @@ -211,7 +214,7 @@ public class CertifyOperation extends BaseOperation { // explicit proxy not set if (!OrbotHelper.isOrbotInRequiredState(mContext)) { return new CertifyResult(null, - RequiredInputParcel.createOrbotRequiredOperation()); + RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput); } proxy = Preferences.getPreferences(mContext).getProxyPrefs() .parcelableProxy.getProxy(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java index 0dec35949..5b13fa629 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java @@ -130,18 +130,6 @@ public class ExportOperation extends BaseOperation { } } - /** - * returns null if no user input required for upload, an InputPendingResult otherwise - */ - @Nullable - public InputPendingResult getUploadPendingInput() { - if (!OrbotHelper.isOrbotInRequiredState(mContext)) { - return new ExportResult(null, - RequiredInputParcel.createOrbotRequiredOperation()); - } - return null; - } - public ExportResult exportToFile(long[] masterKeyIds, boolean exportSecret, String outputFile) { OperationLog log = new OperationLog(); @@ -355,7 +343,7 @@ public class ExportOperation extends BaseOperation { // explicit proxy not set if (!OrbotHelper.isOrbotInRequiredState(mContext)) { return new ExportResult(null, - RequiredInputParcel.createOrbotRequiredOperation()); + RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput); } proxy = Preferences.getPreferences(mContext).getProxyPrefs() .parcelableProxy.getProxy(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java index 256f1bb82..4acfd6e30 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java @@ -404,7 +404,7 @@ public class ImportOperation extends BaseOperation { if(!OrbotHelper.isOrbotInRequiredState(mContext)) { // show dialog to enable/install dialog return new ImportKeyResult(null, - RequiredInputParcel.createOrbotRequiredOperation()); + RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput); } proxy = Preferences.getPreferences(mContext).getProxyPrefs().parcelableProxy .getProxy(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java index 42bd3ace2..30f37dd4f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java @@ -69,7 +69,7 @@ public class KeybaseVerificationOperation extends BaseOperation { RequiredInputParcel requiredInput = result.getRequiredInputParcel(); // Passphrase returns immediately, nfc are aggregated if (requiredInput.mType == RequiredInputType.PASSPHRASE) { - return new SignEncryptResult(log, requiredInput, results); + return new SignEncryptResult(log, requiredInput, results, cryptoInput); } if (pendingInputBuilder == null) { pendingInputBuilder = new NfcSignOperationsBuilder(requiredInput.mSignatureTime, @@ -173,7 +173,7 @@ public class SignEncryptOperation extends BaseOperation { } while (!inputUris.isEmpty()); if (pendingInputBuilder != null && !pendingInputBuilder.isEmpty()) { - return new SignEncryptResult(log, pendingInputBuilder.build(), results); + return new SignEncryptResult(log, pendingInputBuilder.build(), results, cryptoInput); } if (!outputUris.isEmpty()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java index a9f8170d9..cf73f019c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.os.Parcel; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.LogDisplayActivity; import org.sufficientlysecure.keychain.ui.LogDisplayFragment; @@ -38,8 +39,9 @@ public class CertifyResult extends InputPendingResult { super(result, log); } - public CertifyResult(OperationLog log, RequiredInputParcel requiredInput) { - super(log, requiredInput); + public CertifyResult(OperationLog log, RequiredInputParcel requiredInput, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInput, cryptoInputParcel); } public CertifyResult(int result, OperationLog log, int certifyOk, int certifyError, int uploadOk, int uploadError) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java index 25a86f137..972fbb0aa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java @@ -45,8 +45,9 @@ public class DecryptVerifyResult extends InputPendingResult { super(result, log); } - public DecryptVerifyResult(OperationLog log, RequiredInputParcel requiredInput) { - super(log, requiredInput); + public DecryptVerifyResult(OperationLog log, RequiredInputParcel requiredInput, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInput, cryptoInputParcel); } public DecryptVerifyResult(Parcel source) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java index 52c6e1491..c7c48ed56 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java @@ -24,6 +24,7 @@ import android.os.Parcel; import android.support.annotation.Nullable; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.LogDisplayActivity; import org.sufficientlysecure.keychain.ui.LogDisplayFragment; @@ -47,8 +48,9 @@ public class DeleteResult extends InputPendingResult { * @param log operation log upto point of required input, if any * @param requiredInput represents input required */ - public DeleteResult(@Nullable OperationLog log, RequiredInputParcel requiredInput) { - super(log, requiredInput); + public DeleteResult(@Nullable OperationLog log, RequiredInputParcel requiredInput, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInput, cryptoInputParcel); // values are not to be used mOk = -1; mFail = -1; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java index 199a3f565..e21ef949f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; public class ExportResult extends InputPendingResult { @@ -36,8 +37,9 @@ public class ExportResult extends InputPendingResult { } - public ExportResult(OperationLog log, RequiredInputParcel requiredInputParcel) { - super(log, requiredInputParcel); + public ExportResult(OperationLog log, RequiredInputParcel requiredInputParcel, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInputParcel, cryptoInputParcel); // we won't use these values mOkPublic = -1; mOkSecret = -1; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/GetKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/GetKeyResult.java index 15f03e439..bdc4d9a47 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/GetKeyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/GetKeyResult.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; public class GetKeyResult extends InputPendingResult { @@ -38,8 +39,9 @@ public class GetKeyResult extends InputPendingResult { super(result, log); } - public GetKeyResult(OperationLog log, RequiredInputParcel requiredInput) { - super(log, requiredInput); + public GetKeyResult(OperationLog log, RequiredInputParcel requiredInput, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInput, cryptoInputParcel); } public static final int RESULT_ERROR_NO_VALID_KEYS = RESULT_ERROR + 8; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java index ca7079078..5f5090bee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java @@ -96,8 +96,9 @@ public class ImportKeyResult extends InputPendingResult { mImportedMasterKeyIds = importedMasterKeyIds; } - public ImportKeyResult(OperationLog log, RequiredInputParcel requiredInputParcel) { - super(log, requiredInputParcel); + public ImportKeyResult(OperationLog log, RequiredInputParcel requiredInputParcel, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInputParcel, cryptoInputParcel); // just assign default values, we won't use them anyway mNewKeys = 0; mUpdatedKeys = 0; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java index 5b982ca61..f055c450c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java @@ -32,7 +32,7 @@ public class InputPendingResult extends OperationResult { final RequiredInputParcel mRequiredInput; // in case operation needs to add to/changes the cryptoInputParcel sent to it - final CryptoInputParcel mCryptoInputParcel; + public final CryptoInputParcel mCryptoInputParcel; public InputPendingResult(int result, OperationLog log) { super(result, log); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/KeybaseVerificationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/KeybaseVerificationResult.java index 173f7f575..84648d32c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/KeybaseVerificationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/KeybaseVerificationResult.java @@ -24,6 +24,7 @@ import android.os.Parcelable; import com.textuality.keybase.lib.KeybaseException; import com.textuality.keybase.lib.prover.Prover; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; public class KeybaseVerificationResult extends InputPendingResult { @@ -46,8 +47,9 @@ public class KeybaseVerificationResult extends InputPendingResult { mPresenceLabel = prover.getPresenceLabel(); } - public KeybaseVerificationResult(OperationLog log, RequiredInputParcel requiredInputParcel) { - super(log, requiredInputParcel); + public KeybaseVerificationResult(OperationLog log, RequiredInputParcel requiredInputParcel, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInputParcel, cryptoInputParcel); mProofUrl = null; mPresenceUrl = null; mPresenceLabel = null; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpEditKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpEditKeyResult.java index 38edbf6ee..30307ba46 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpEditKeyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpEditKeyResult.java @@ -22,6 +22,7 @@ import android.os.Parcel; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -37,8 +38,9 @@ public class PgpEditKeyResult extends InputPendingResult { mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : Constants.key.none; } - public PgpEditKeyResult(OperationLog log, RequiredInputParcel requiredInput) { - super(log, requiredInput); + public PgpEditKeyResult(OperationLog log, RequiredInputParcel requiredInput, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInput, cryptoInputParcel); mRingMasterKeyId = Constants.key.none; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java index acb265462..2b33b8ace 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -38,8 +39,9 @@ public class PgpSignEncryptResult extends InputPendingResult { super(result, log); } - public PgpSignEncryptResult(OperationLog log, RequiredInputParcel requiredInput) { - super(log, requiredInput); + public PgpSignEncryptResult(OperationLog log, RequiredInputParcel requiredInput, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInput, cryptoInputParcel); } public PgpSignEncryptResult(Parcel source) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java index 4b4892b05..160c030fd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java @@ -7,6 +7,7 @@ import android.os.Parcelable; import android.support.annotation.Nullable; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.LogDisplayActivity; import org.sufficientlysecure.keychain.ui.LogDisplayFragment; @@ -26,8 +27,9 @@ public class RevokeResult extends InputPendingResult { * @param log operation log upto point of required input, if any * @param requiredInput represents input required */ - public RevokeResult(@Nullable OperationLog log, RequiredInputParcel requiredInput) { - super(log, requiredInput); + public RevokeResult(@Nullable OperationLog log, RequiredInputParcel requiredInput, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInput, cryptoInputParcel); // we won't use these values mMasterKeyId = -1; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java index b05921b0d..39213b796 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java @@ -21,6 +21,7 @@ import android.os.Parcel; import java.util.ArrayList; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -29,8 +30,10 @@ public class SignEncryptResult extends InputPendingResult { ArrayList mResults; byte[] mResultBytes; - public SignEncryptResult(OperationLog log, RequiredInputParcel requiredInput, ArrayList results) { - super(log, requiredInput); + public SignEncryptResult(OperationLog log, RequiredInputParcel requiredInput, + ArrayList results, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInput, cryptoInputParcel); mResults = results; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index 7b61968a3..e264b4678 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -459,7 +459,8 @@ public class PgpDecryptVerify extends BaseOperation log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1); return new DecryptVerifyResult(log, RequiredInputParcel.createRequiredDecryptPassphrase( - secretKeyRing.getMasterKeyId(), secretEncryptionKey.getKeyId())); + secretKeyRing.getMasterKeyId(), secretEncryptionKey.getKeyId()), + cryptoInput); } } @@ -498,7 +499,8 @@ public class PgpDecryptVerify extends BaseOperation if (passphrase == null) { log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1); return new DecryptVerifyResult(log, - RequiredInputParcel.createRequiredSymmetricPassphrase()); + RequiredInputParcel.createRequiredSymmetricPassphrase(), + cryptoInput); } } else { @@ -544,7 +546,7 @@ public class PgpDecryptVerify extends BaseOperation } catch (PGPDataValidationException e) { log.add(LogType.MSG_DC_ERROR_SYM_PASSPHRASE, indent +1); return new DecryptVerifyResult(log, - RequiredInputParcel.createRequiredSymmetricPassphrase()); + RequiredInputParcel.createRequiredSymmetricPassphrase(), cryptoInput); } encryptedData = encryptedDataSymmetric; @@ -580,7 +582,8 @@ public class PgpDecryptVerify extends BaseOperation return new DecryptVerifyResult(log, RequiredInputParcel.createNfcDecryptOperation( secretEncryptionKey.getRing().getMasterKeyId(), secretEncryptionKey.getKeyId(), encryptedDataAsymmetric.getSessionKey()[0] - )); + ), + cryptoInput); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 5eaa03394..565a3bb79 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -469,7 +469,7 @@ public class PgpKeyOperation { log.add(LogType.MSG_MF_REQUIRE_PASSPHRASE, indent); return new PgpEditKeyResult(log, RequiredInputParcel.createRequiredSignPassphrase( masterSecretKey.getKeyID(), masterSecretKey.getKeyID(), - cryptoInput.getSignatureTime())); + cryptoInput.getSignatureTime()), cryptoInput); } // read masterKeyFlags, and use the same as before. @@ -1105,12 +1105,12 @@ public class PgpKeyOperation { if (!nfcSignOps.isEmpty()) { log.add(LogType.MSG_MF_REQUIRE_DIVERT, indent); - return new PgpEditKeyResult(log, nfcSignOps.build()); + return new PgpEditKeyResult(log, nfcSignOps.build(), cryptoInput); } if (!nfcKeyToCardOps.isEmpty()) { log.add(LogType.MSG_MF_REQUIRE_DIVERT, indent); - return new PgpEditKeyResult(log, nfcKeyToCardOps.build()); + return new PgpEditKeyResult(log, nfcKeyToCardOps.build(), cryptoInput); } log.add(LogType.MSG_MF_SUCCESS, indent); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java index 0448e1425..a878b4b29 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -200,7 +200,7 @@ public class PgpSignEncryptOperation extends BaseOperation { log.add(LogType.MSG_PSE_PENDING_PASSPHRASE, indent + 1); return new PgpSignEncryptResult(log, RequiredInputParcel.createRequiredSignPassphrase( signingKeyRing.getMasterKeyId(), signingKey.getKeyId(), - cryptoInput.getSignatureTime())); + cryptoInput.getSignatureTime()), cryptoInput); } if (!signingKey.unlock(localPassphrase)) { log.add(LogType.MSG_PSE_ERROR_BAD_PASSPHRASE, indent); @@ -513,7 +513,7 @@ public class PgpSignEncryptOperation extends BaseOperation { log.add(LogType.MSG_PSE_PENDING_NFC, indent); return new PgpSignEncryptResult(log, RequiredInputParcel.createNfcSignOperation( signingKey.getRing().getMasterKeyId(), signingKey.getKeyId(), - e.hashToSign, e.hashAlgo, cryptoInput.getSignatureTime())); + e.hashToSign, e.hashAlgo, cryptoInput.getSignatureTime()), cryptoInput); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java index adf46caf8..4b779e75c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java @@ -27,6 +27,7 @@ import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.keyimport.Keyserver; import org.sufficientlysecure.keychain.operations.results.GetKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ParcelableProxy; @@ -121,7 +122,8 @@ public class ImportKeysListCloudLoader // user needs to enable/install orbot mEntryList.clear(); GetKeyResult pendingResult = new GetKeyResult(null, - RequiredInputParcel.createOrbotRequiredOperation()); + RequiredInputParcel.createOrbotRequiredOperation(), + new CryptoInputParcel()); mEntryListWrapper = new AsyncTaskResultWrapper<>(mEntryList, pendingResult); return; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java index 398b3e778..f703ebbde 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java @@ -269,7 +269,7 @@ public class CryptoOperationHelper Date: Fri, 10 Jul 2015 05:21:56 +0530 Subject: added retry on upload failure --- OpenKeychain/src/main/AndroidManifest.xml | 3 + .../keychain/operations/EditKeyOperation.java | 6 +- .../keychain/operations/ExportOperation.java | 3 + .../keychain/operations/results/EditKeyResult.java | 9 +++ .../keychain/service/input/CryptoInputParcel.java | 1 + .../service/input/RequiredInputParcel.java | 6 ++ .../keychain/ui/UploadRetryDialogActivity.java | 68 ++++++++++++++++++++++ .../keychain/ui/base/CryptoOperationHelper.java | 25 ++++++-- OpenKeychain/src/main/res/values/strings.xml | 6 ++ 9 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadRetryDialogActivity.java (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index c5b1d1a3d..68c2aefa8 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -682,6 +682,9 @@ + diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java index 6a1c01dd1..8c1bbc0c2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -41,6 +41,7 @@ import org.sufficientlysecure.keychain.service.ExportKeyringParcel; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ProgressScaler; @@ -137,13 +138,14 @@ public class EditKeyOperation extends BaseOperation { new ExportKeyringParcel(saveParcel.getUploadKeyserver(), ring); ExportResult uploadResult = new ExportOperation(mContext, mProviderHelper, mProgressable) - .execute(exportKeyringParcel, cryptoInput); + .execute(exportKeyringParcel, cryptoInput); if (uploadResult.isPending()) { return uploadResult; } else if (!uploadResult.success() && saveParcel.isUploadAtomic()) { // if atomic, update fail implies edit operation should also fail and not save log.add(uploadResult, 2); - return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, saveParcel.mMasterKeyId); + return new EditKeyResult(log, RequiredInputParcel.createRetryUploadOperation(), + cryptoInput); } else { // upload succeeded or not atomic so we continue log.add(uploadResult, 2); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java index 5b13fa629..b8b2aebf5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java @@ -91,6 +91,8 @@ public class ExportOperation extends BaseOperation { } public ExportResult uploadKeyRingToServer(HkpKeyserver server, UncachedKeyRing keyring, Proxy proxy) { + mProgressable.setProgress(R.string.progress_uploading, 0, 1); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); ArmoredOutputStream aos = null; OperationLog log = new OperationLog(); @@ -119,6 +121,7 @@ public class ExportOperation extends BaseOperation { log.add(LogType.MSG_EXPORT_ERROR_UPLOAD, 1); return new ExportResult(ExportResult.RESULT_ERROR, log); } finally { + mProgressable.setProgress(R.string.progress_uploading, 1, 1); try { if (aos != null) { aos.close(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java index b9407a864..6098d59d5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java @@ -20,6 +20,9 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; + public class EditKeyResult extends InputPendingResult { public final Long mMasterKeyId; @@ -29,6 +32,12 @@ public class EditKeyResult extends InputPendingResult { mMasterKeyId = masterKeyId; } + public EditKeyResult(OperationLog log, RequiredInputParcel requiredInput, + CryptoInputParcel cryptoInputParcel) { + super(log, requiredInput, cryptoInputParcel); + mMasterKeyId = null; + } + public EditKeyResult(Parcel source) { super(source); mMasterKeyId = source.readInt() != 0 ? source.readLong() : null; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java index 9ba9601e5..e553b9b0f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.service.input; import android.os.Parcel; import android.os.Parcelable; +import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.Passphrase; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java index 8eef8de8d..8c9d54769 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java @@ -16,6 +16,7 @@ public class RequiredInputParcel implements Parcelable { public enum RequiredInputType { PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_MOVE_KEY_TO_CARD, ENABLE_ORBOT, + UPLOAD_FAIL_RETRY } public Date mSignatureTime; @@ -77,6 +78,11 @@ public class RequiredInputParcel implements Parcelable { return mSubKeyId; } + public static RequiredInputParcel createRetryUploadOperation() { + return new RequiredInputParcel(RequiredInputType.UPLOAD_FAIL_RETRY, + null, null, null, 0L, 0L); + } + public static RequiredInputParcel createOrbotRequiredOperation() { return new RequiredInputParcel(RequiredInputType.ENABLE_ORBOT, null, null, null, 0L, 0L); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadRetryDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadRetryDialogActivity.java new file mode 100644 index 000000000..8575d5035 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadRetryDialogActivity.java @@ -0,0 +1,68 @@ +package org.sufficientlysecure.keychain.ui; + +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentActivity; +import android.view.ContextThemeWrapper; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; + +public class UploadRetryDialogActivity extends FragmentActivity { + + public static final String EXTRA_CRYPTO_INPUT = "extra_crypto_input"; + + public static final String RESULT_CRYPTO_INPUT = "result_crypto_input"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + UploadRetryDialogFragment.newInstance().show(getSupportFragmentManager(), + "uploadRetryDialog"); + } + + public static class UploadRetryDialogFragment extends DialogFragment { + public static UploadRetryDialogFragment newInstance() { + return new UploadRetryDialogFragment(); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + ContextThemeWrapper theme = new ContextThemeWrapper(getActivity(), + R.style.Theme_AppCompat_Light_Dialog); + + CustomAlertDialogBuilder dialogBuilder = new CustomAlertDialogBuilder(theme); + dialogBuilder.setTitle(R.string.retry_up_dialog_title); + dialogBuilder.setMessage(R.string.retry_up_dialog_message); + + dialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + getActivity().setResult(RESULT_CANCELED); + getActivity().finish(); + } + }); + + dialogBuilder.setPositiveButton(R.string.retry_up_dialog_btn_reupload, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Intent intent = new Intent(); + intent.putExtra(RESULT_CRYPTO_INPUT, getActivity() + .getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT)); + getActivity().setResult(RESULT_OK, intent); + getActivity().finish(); + } + }); + + return dialogBuilder.show(); + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java index f703ebbde..b6e294579 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java @@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.NfcOperationActivity; import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity; import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; +import org.sufficientlysecure.keychain.ui.UploadRetryDialogActivity; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.util.Log; @@ -76,6 +77,7 @@ public class CryptoOperationHelper"Share with QR Code" "Share with NFC" + + "Upload failed" + "Upload failed. Would you like to retry the operation?" + "Retry Operation" + "Cancel Operation" + "If you would no longer like to use this key, it should be revoked and uploaded. Select delete only if you wish to remove the key from OpenKeychain but continue to use it from somewhere else." "Revoke/Delete key" -- cgit v1.2.3 From b61a7d55351eca32833662f623c2e42559c587f7 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Fri, 10 Jul 2015 06:17:31 +0530 Subject: added licenses, cleaned up code, fixed warnings --- OpenKeychain/src/main/AndroidManifest.xml | 2 +- .../keychain/operations/DeleteOperation.java | 9 --- .../keychain/operations/EditKeyOperation.java | 13 ++-- .../keychain/operations/ExportOperation.java | 3 - .../keychain/operations/RevokeOperation.java | 20 ++++- .../operations/results/DecryptVerifyResult.java | 1 - .../operations/results/InputPendingResult.java | 2 - .../keychain/operations/results/RevokeResult.java | 21 ++++++ .../operations/results/SignEncryptResult.java | 3 +- .../keychain/pgp/PgpSignEncryptOperation.java | 1 - .../keychain/pgp/UncachedKeyRing.java | 2 - .../keychain/service/ExportKeyringParcel.java | 1 + .../keychain/service/RevokeKeyringParcel.java | 19 +++++ .../keychain/service/SaveKeyringParcel.java | 1 + .../keychain/service/input/CryptoInputParcel.java | 1 - .../service/input/RequiredInputParcel.java | 1 - .../keychain/ui/DeleteKeyDialogActivity.java | 46 ++++++----- .../keychain/ui/EditKeyFragment.java | 1 - .../keychain/ui/KeyListFragment.java | 9 +-- .../keychain/ui/RetryUploadDialogActivity.java | 88 ++++++++++++++++++++++ .../keychain/ui/UploadRetryDialogActivity.java | 68 ----------------- .../keychain/ui/ViewKeyActivity.java | 5 +- .../ui/adapter/ImportKeysListCloudLoader.java | 11 +-- .../keychain/ui/base/CryptoOperationHelper.java | 8 +- .../src/main/res/layout/del_rev_dialog.xml | 5 +- 25 files changed, 199 insertions(+), 142 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RetryUploadDialogActivity.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadRetryDialogActivity.java (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index 68c2aefa8..83d8bce91 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -683,7 +683,7 @@ android:name=".ui.PassphraseDialogActivity" android:theme="@android:style/Theme.NoDisplay" /> * This operation provides a higher level interface to the edit and * create key operations in PgpKeyOperation. It takes care of fetching * and saving the key before and after the operation. @@ -67,7 +66,7 @@ public class EditKeyOperation extends BaseOperation { * Saves an edited key, and uploads it to a server atomically or otherwise as * specified in saveParcel * - * @param saveParcel primary input to the operation + * @param saveParcel primary input to the operation * @param cryptoInput input that changes if user interaction is required * @return the result of the operation */ @@ -137,8 +136,8 @@ public class EditKeyOperation extends BaseOperation { ExportKeyringParcel exportKeyringParcel = new ExportKeyringParcel(saveParcel.getUploadKeyserver(), ring); ExportResult uploadResult = - new ExportOperation(mContext, mProviderHelper, mProgressable) - .execute(exportKeyringParcel, cryptoInput); + new ExportOperation(mContext, mProviderHelper, mProgressable) + .execute(exportKeyringParcel, cryptoInput); if (uploadResult.isPending()) { return uploadResult; } else if (!uploadResult.success() && saveParcel.isUploadAtomic()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java index b8b2aebf5..a5b70a41f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java @@ -18,7 +18,6 @@ package org.sufficientlysecure.keychain.operations; - import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -34,7 +33,6 @@ import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.TextUtils; import org.spongycastle.bcpg.ArmoredOutputStream; @@ -43,7 +41,6 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException; import org.sufficientlysecure.keychain.operations.results.ExportResult; -import org.sufficientlysecure.keychain.operations.results.InputPendingResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java index 0fc3f1bc3..ecf64e1af 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2013-2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser + * Copyright (C) 2015 Adithya Abraham Philip + * + * 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 . + */ + package org.sufficientlysecure.keychain.operations; import android.content.Context; @@ -6,7 +25,6 @@ import android.net.Uri; import android.support.annotation.NonNull; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.operations.results.DeleteResult; import org.sufficientlysecure.keychain.operations.results.InputPendingResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.RevokeResult; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java index 972fbb0aa..f9a738d56 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java @@ -24,7 +24,6 @@ import org.openintents.openpgp.OpenPgpMetadata; import org.openintents.openpgp.OpenPgpSignatureResult; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; -import org.sufficientlysecure.keychain.util.Passphrase; public class DecryptVerifyResult extends InputPendingResult { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java index f055c450c..d767382ae 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java @@ -18,8 +18,6 @@ package org.sufficientlysecure.keychain.operations.results; -import java.util.ArrayList; - import android.os.Parcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java index 160c030fd..b737f6e50 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/RevokeResult.java @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2013-2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser + * Copyright (C) 2015 Adithya Abraham Philip + * + * 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 . + */ + package org.sufficientlysecure.keychain.operations.results; import android.app.Activity; @@ -24,9 +43,11 @@ public class RevokeResult extends InputPendingResult { /** * used when more input is required + * * @param log operation log upto point of required input, if any * @param requiredInput represents input required */ + @SuppressWarnings("unused") // standard pattern across all results, we might need it later public RevokeResult(@Nullable OperationLog log, RequiredInputParcel requiredInput, CryptoInputParcel cryptoInputParcel) { super(log, requiredInput, cryptoInputParcel); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java index 39213b796..0e0c5d598 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java @@ -19,11 +19,10 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; -import java.util.ArrayList; - import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; +import java.util.ArrayList; public class SignEncryptResult extends InputPendingResult { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java index a878b4b29..8fb41a909 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -43,7 +43,6 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogTyp import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index f4a8fa494..a7baddf8b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -18,8 +18,6 @@ package org.sufficientlysecure.keychain.pgp; -import android.os.Parcelable; - import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.PublicKeyAlgorithmTags; import org.spongycastle.bcpg.SignatureSubpacketTags; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java index a8b901ab0..24c002bbd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java @@ -61,6 +61,7 @@ public class ExportKeyringParcel implements Parcelable { mOutputFile = outputFile; } + @SuppressWarnings("unused") // TODO: is it used? public ExportKeyringParcel(long[] masterKeyIds, boolean exportSecret, Uri outputUri) { mExportType = ExportType.EXPORT_URI; mMasterKeyIds = masterKeyIds; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java index b5da31c59..02e8fda46 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/RevokeKeyringParcel.java @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2013-2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser + * Copyright (C) 2015 Adithya Abraham Philip + * + * 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 . + */ + package org.sufficientlysecure.keychain.service; import android.os.Parcel; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index fcb95493b..6959fca56 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -242,6 +242,7 @@ public class SaveKeyringParcel implements Parcelable { } } + @SuppressWarnings("unchecked") // we verify the reads against writes in writeToParcel public SaveKeyringParcel(Parcel source) { mMasterKeyId = source.readInt() != 0 ? source.readLong() : null; mFingerprint = source.createByteArray(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java index e553b9b0f..9ba9601e5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.service.input; import android.os.Parcel; import android.os.Parcelable; -import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.Passphrase; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java index 8c9d54769..e4dac3227 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java @@ -3,7 +3,6 @@ package org.sufficientlysecure.keychain.service.input; import android.os.Parcel; import android.os.Parcelable; -import org.spongycastle.util.Arrays; import org.sufficientlysecure.keychain.util.Passphrase; import java.nio.ByteBuffer; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java index 98d3cf7b0..bf91d3064 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2013-2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser + * Copyright (C) 2015 Adithya Abraham Philip + * + * 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 . + */ + package org.sufficientlysecure.keychain.ui; import android.app.Activity; @@ -6,12 +25,7 @@ import android.app.Dialog; import android.content.DialogInterface; 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.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; import android.view.ContextThemeWrapper; @@ -47,7 +61,6 @@ public class DeleteKeyDialogActivity extends FragmentActivity { private CryptoOperationHelper mRevokeOpHelper; private long[] mMasterKeyIds; - private boolean mHasSecret; @Override protected void onCreate(Bundle savedInstanceState) { @@ -60,14 +73,14 @@ public class DeleteKeyDialogActivity extends FragmentActivity { getRevocationCallback(), R.string.progress_revoking_uploading); mMasterKeyIds = getIntent().getLongArrayExtra(EXTRA_DELETE_MASTER_KEY_IDS); - mHasSecret = getIntent().getBooleanExtra(EXTRA_HAS_SECRET, false); + boolean hasSecret = getIntent().getBooleanExtra(EXTRA_HAS_SECRET, false); - if (mMasterKeyIds.length > 1 && mHasSecret) { + if (mMasterKeyIds.length > 1 && hasSecret) { throw new AssertionError("Secret keys can be deleted only one at a time!" + " Should be checked before reaching DeleteKeyDialogActivity."); } - if (mMasterKeyIds.length == 1 && mHasSecret) { + if (mMasterKeyIds.length == 1 && hasSecret) { // if mMasterKeyIds.length == 0 we let the DeleteOperation respond try { HashMap data = new ProviderHelper(this).getUnifiedData( @@ -89,7 +102,6 @@ public class DeleteKeyDialogActivity extends FragmentActivity { "Secret key to delete not found at DeleteKeyDialogActivity for " + mMasterKeyIds[0], e); finish(); - return; } } else { showNormalDeleteDialog(); @@ -121,8 +133,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { private CryptoOperationHelper.Callback getRevocationCallback() { - CryptoOperationHelper.Callback callback - = new CryptoOperationHelper.Callback() { + return new CryptoOperationHelper.Callback() { @Override public RevokeKeyringParcel createOperationInput() { return new RevokeKeyringParcel(mMasterKeyIds[0], true, @@ -150,14 +161,11 @@ public class DeleteKeyDialogActivity extends FragmentActivity { return false; } }; - - return callback; } private CryptoOperationHelper.Callback getDeletionCallback() { - CryptoOperationHelper.Callback callback - = new CryptoOperationHelper.Callback() { + return new CryptoOperationHelper.Callback() { @Override public DeleteKeyringParcel createOperationInput() { return new DeleteKeyringParcel(mMasterKeyIds, true); @@ -184,8 +192,6 @@ public class DeleteKeyDialogActivity extends FragmentActivity { return false; } }; - - return callback; } private void returnResult(OperationResult result) { @@ -305,10 +311,10 @@ public class DeleteKeyDialogActivity extends FragmentActivity { public static class RevokeDeleteDialogFragment extends DialogFragment { public static RevokeDeleteDialogFragment newInstance() { - RevokeDeleteDialogFragment frag = new RevokeDeleteDialogFragment(); - return frag; + return new RevokeDeleteDialogFragment(); } + @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final Activity activity = getActivity(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index f750c6d97..4e9c5a836 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -410,7 +410,6 @@ public class EditKeyFragment extends QueueingCryptoOperationFragment 1) { Notify.create(getActivity(), R.string.secret_cannot_multiple, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RetryUploadDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RetryUploadDialogActivity.java new file mode 100644 index 000000000..85f2096db --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/RetryUploadDialogActivity.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2013-2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser + * Copyright (C) 2015 Adithya Abraham Philip + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentActivity; +import android.view.ContextThemeWrapper; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; + +public class RetryUploadDialogActivity extends FragmentActivity { + + public static final String EXTRA_CRYPTO_INPUT = "extra_crypto_input"; + + public static final String RESULT_CRYPTO_INPUT = "result_crypto_input"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + UploadRetryDialogFragment.newInstance().show(getSupportFragmentManager(), + "uploadRetryDialog"); + } + + public static class UploadRetryDialogFragment extends DialogFragment { + public static UploadRetryDialogFragment newInstance() { + return new UploadRetryDialogFragment(); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + ContextThemeWrapper theme = new ContextThemeWrapper(getActivity(), + R.style.Theme_AppCompat_Light_Dialog); + + CustomAlertDialogBuilder dialogBuilder = new CustomAlertDialogBuilder(theme); + dialogBuilder.setTitle(R.string.retry_up_dialog_title); + dialogBuilder.setMessage(R.string.retry_up_dialog_message); + + dialogBuilder.setNegativeButton(R.string.retry_up_dialog_btn_cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + getActivity().setResult(RESULT_CANCELED); + getActivity().finish(); + } + }); + + dialogBuilder.setPositiveButton(R.string.retry_up_dialog_btn_reupload, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Intent intent = new Intent(); + intent.putExtra(RESULT_CRYPTO_INPUT, getActivity() + .getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT)); + getActivity().setResult(RESULT_OK, intent); + getActivity().finish(); + } + }); + + return dialogBuilder.show(); + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadRetryDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadRetryDialogActivity.java deleted file mode 100644 index 8575d5035..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadRetryDialogActivity.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.sufficientlysecure.keychain.ui; - -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentActivity; -import android.view.ContextThemeWrapper; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; - -public class UploadRetryDialogActivity extends FragmentActivity { - - public static final String EXTRA_CRYPTO_INPUT = "extra_crypto_input"; - - public static final String RESULT_CRYPTO_INPUT = "result_crypto_input"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - UploadRetryDialogFragment.newInstance().show(getSupportFragmentManager(), - "uploadRetryDialog"); - } - - public static class UploadRetryDialogFragment extends DialogFragment { - public static UploadRetryDialogFragment newInstance() { - return new UploadRetryDialogFragment(); - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - - ContextThemeWrapper theme = new ContextThemeWrapper(getActivity(), - R.style.Theme_AppCompat_Light_Dialog); - - CustomAlertDialogBuilder dialogBuilder = new CustomAlertDialogBuilder(theme); - dialogBuilder.setTitle(R.string.retry_up_dialog_title); - dialogBuilder.setMessage(R.string.retry_up_dialog_message); - - dialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - getActivity().setResult(RESULT_CANCELED); - getActivity().finish(); - } - }); - - dialogBuilder.setPositiveButton(R.string.retry_up_dialog_btn_reupload, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Intent intent = new Intent(); - intent.putExtra(RESULT_CRYPTO_INPUT, getActivity() - .getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT)); - getActivity().setResult(RESULT_OK, intent); - getActivity().finish(); - } - }); - - return dialogBuilder.show(); - } - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 08ef38746..938dbc9f2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -31,8 +31,6 @@ import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.Message; -import android.os.Messenger; import android.provider.ContactsContract; import android.support.v4.app.ActivityCompat; import android.support.v4.app.FragmentManager; @@ -52,7 +50,9 @@ import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; + import com.getbase.floatingactionbutton.FloatingActionButton; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; @@ -65,7 +65,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; -import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus; import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java index 4b779e75c..e77c92923 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java @@ -49,12 +49,13 @@ public class ImportKeysListCloudLoader private AsyncTaskResultWrapper> mEntryListWrapper; /** - * Pass a parcelableProxy to specify an explicit proxy, otherwise will fetch from preferences + * Searches a keyserver as specified in cloudPrefs, using an explicit proxy if passed * - * @param context - * @param serverQuery - * @param cloudPrefs - * @param parcelableProxy + * @param serverQuery string to search on servers for. If is a fingerprint, + * will enforce fingerprint check + * @param cloudPrefs contains keyserver to search on, whether to search on the keyserver, + * and whether to search keybase.io + * @param parcelableProxy explicit proxy to use. If null, will retrieve from preferences */ public ImportKeysListCloudLoader(Context context, String serverQuery, Preferences.CloudSearchPrefs cloudPrefs, @Nullable ParcelableProxy parcelableProxy) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java index b6e294579..932b6c007 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java @@ -40,7 +40,7 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.NfcOperationActivity; import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity; import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; -import org.sufficientlysecure.keychain.ui.UploadRetryDialogActivity; +import org.sufficientlysecure.keychain.ui.RetryUploadDialogActivity; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.util.Log; @@ -148,8 +148,8 @@ public class CryptoOperationHelper + android:entries="@array/rev_del_dialog_entries"/> - \ No newline at end of file + -- cgit v1.2.3 From 76500f47a3e85347204c029f9ef6817504b276c7 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Fri, 10 Jul 2015 07:18:00 +0530 Subject: made key deletion require double confirmation --- .../org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java index bf91d3064..57b74f1be 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -357,7 +357,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { .startRevocationOperation(); } else if (choice.equals(CHOICE_DELETE)) { ((DeleteKeyDialogActivity) activity) - .startDeletionOperation(); + .showNormalDeleteDialog(); } else { throw new AssertionError( "Unsupported delete type in RevokeDeleteDialogFragment"); -- cgit v1.2.3 From 0cec75fc9d47c4728678418727559e523295ae21 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Fri, 10 Jul 2015 07:47:38 +0530 Subject: show key name on revoke/delete dialog --- .../keychain/ui/DeleteKeyDialogActivity.java | 29 +++++++++++++++++----- OpenKeychain/src/main/res/values/strings.xml | 2 +- 2 files changed, 24 insertions(+), 7 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java index 57b74f1be..ec9d7d74c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -92,10 +92,20 @@ public class DeleteKeyDialogActivity extends FragmentActivity { ProviderHelper.FIELD_TYPE_INTEGER } ); + + String name; + KeyRing.UserId mainUserId = KeyRing.splitUserId( + (String) data.get(KeychainContract.KeyRings.USER_ID)); + if (mainUserId.name != null) { + name = mainUserId.name; + } else { + name = getString(R.string.user_id_no_name); + } + if ((long) data.get(KeychainContract.KeyRings.IS_REVOKED) > 0) { showNormalDeleteDialog(); } else { - showRevokeDeleteDialog(); + showRevokeDeleteDialog(name); } } catch (ProviderHelper.NotFoundException e) { Log.e(Constants.TAG, @@ -117,9 +127,9 @@ public class DeleteKeyDialogActivity extends FragmentActivity { } - private void showRevokeDeleteDialog() { + private void showRevokeDeleteDialog(String keyname) { - RevokeDeleteDialogFragment fragment = RevokeDeleteDialogFragment.newInstance(); + RevokeDeleteDialogFragment fragment = RevokeDeleteDialogFragment.newInstance(keyname); fragment.show(getSupportFragmentManager(), "deleteRevokeDialog"); } @@ -310,8 +320,14 @@ public class DeleteKeyDialogActivity extends FragmentActivity { public static class RevokeDeleteDialogFragment extends DialogFragment { - public static RevokeDeleteDialogFragment newInstance() { - return new RevokeDeleteDialogFragment(); + public static final String ARG_KEY_NAME = "arg_key_name"; + + public static RevokeDeleteDialogFragment newInstance(String keyName) { + Bundle args = new Bundle(); + args.putString(ARG_KEY_NAME, keyName); + RevokeDeleteDialogFragment frag = new RevokeDeleteDialogFragment(); + frag.setArguments(args); + return frag; } @NonNull @@ -328,7 +344,8 @@ public class DeleteKeyDialogActivity extends FragmentActivity { R.style.Theme_AppCompat_Light_Dialog); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); - alert.setTitle(R.string.del_rev_dialog_title); + alert.setTitle(getString(R.string.del_rev_dialog_title, + getArguments().get(ARG_KEY_NAME))); LayoutInflater inflater = LayoutInflater.from(theme); View view = inflater.inflate(R.layout.del_rev_dialog, null); diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 88c3f0a5e..1b07886cf 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -599,7 +599,7 @@ "If you would no longer like to use this key, it should be revoked and uploaded. Select delete only if you wish to remove the key from OpenKeychain but continue to use it from somewhere else." - "Revoke/Delete key" + "Revoke/Delete key \"%s\"" "Revoke and upload" "Delete only" -- cgit v1.2.3 From 8bbc5513d447d186497023ca3f0c474541419389 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Fri, 10 Jul 2015 08:29:29 +0530 Subject: corrected DeleteKeyDialogActivity finishing on cancel --- .../keychain/ui/DeleteKeyDialogActivity.java | 30 +++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java index ec9d7d74c..148ca3346 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -310,12 +310,19 @@ public class DeleteKeyDialogActivity extends FragmentActivity { @Override public void onClick(DialogInterface dialog, int id) { - getActivity().finish(); + dialog.cancel(); } }); return builder.show(); } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + getActivity().setResult(RESULT_CANCELED); + getActivity().finish(); + } } public static class RevokeDeleteDialogFragment extends DialogFragment { @@ -343,27 +350,25 @@ public class DeleteKeyDialogActivity extends FragmentActivity { ContextThemeWrapper theme = new ContextThemeWrapper(activity, R.style.Theme_AppCompat_Light_Dialog); - CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); - alert.setTitle(getString(R.string.del_rev_dialog_title, + CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(theme); + builder.setTitle(getString(R.string.del_rev_dialog_title, getArguments().get(ARG_KEY_NAME))); LayoutInflater inflater = LayoutInflater.from(theme); View view = inflater.inflate(R.layout.del_rev_dialog, null); - alert.setView(view); + builder.setView(view); final Spinner spinner = (Spinner) view.findViewById(R.id.spinner); - alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { dialog.cancel(); - activity.setResult(RESULT_CANCELED); - activity.finish(); } }); - alert.setPositiveButton(R.string.del_rev_dialog_btn_revoke, + builder.setPositiveButton(R.string.del_rev_dialog_btn_revoke, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -382,7 +387,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { } }); - final AlertDialog alertDialog = alert.show(); + final AlertDialog alertDialog = builder.show(); spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { public void onItemSelected(AdapterView parent, View view, int pos, long id) { @@ -407,6 +412,13 @@ public class DeleteKeyDialogActivity extends FragmentActivity { return alertDialog; } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + getActivity().setResult(RESULT_CANCELED); + getActivity().finish(); + } } } -- cgit v1.2.3 From c59196a6f1e5dd4e3b2ac864067cc7f469de01ac Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Sat, 11 Jul 2015 03:55:50 +0530 Subject: upload only public key in revocation --- .../keychain/operations/EditKeyOperation.java | 14 +++++++++++++- .../keychain/operations/results/OperationResult.java | 2 ++ OpenKeychain/src/main/res/values/strings.xml | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java index 44106bba8..f5ba88502 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ProgressScaler; +import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -133,11 +134,22 @@ public class EditKeyOperation extends BaseOperation { UncachedKeyRing ring = modifyResult.getRing(); if (saveParcel.isUpload()) { + UncachedKeyRing publicKeyRing; + try { + publicKeyRing = ring.extractPublicKeyRing(); + } catch (IOException e) { + log.add(LogType.MSG_ED_ERROR_EXTRACTING_PUBLIC_UPLOAD, 1); + return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null); + } + ExportKeyringParcel exportKeyringParcel = - new ExportKeyringParcel(saveParcel.getUploadKeyserver(), ring); + new ExportKeyringParcel(saveParcel.getUploadKeyserver(), + publicKeyRing); + ExportResult uploadResult = new ExportOperation(mContext, mProviderHelper, mProgressable) .execute(exportKeyringParcel, cryptoInput); + if (uploadResult.isPending()) { return uploadResult; } else if (!uploadResult.success() && saveParcel.isUploadAtomic()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index c65412a1f..d4b3c433f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -571,6 +571,8 @@ public abstract class OperationResult implements Parcelable { MSG_ED_CACHING_NEW (LogLevel.DEBUG, R.string.msg_ed_caching_new), MSG_ED_ERROR_NO_PARCEL (LogLevel.ERROR, R.string.msg_ed_error_no_parcel), MSG_ED_ERROR_KEY_NOT_FOUND (LogLevel.ERROR, R.string.msg_ed_error_key_not_found), + MSG_ED_ERROR_EXTRACTING_PUBLIC_UPLOAD (LogLevel.ERROR, + R.string.msg_ed_error_extract_public_upload), MSG_ED_FETCHING (LogLevel.DEBUG, R.string.msg_ed_fetching), MSG_ED_SUCCESS (LogLevel.OK, R.string.msg_ed_success), diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 1b07886cf..db81963c1 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1096,6 +1096,7 @@ "Caching new password" "Missing SaveKeyringParcel! (this is a bug, please report)" "Key not found!" + "Error extracting public key for upload!" "Fetching key to modify (%s)" "Key operation successful" -- cgit v1.2.3 From c1d2beb55986138a21a40cc6ba6d64684e1798dc Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Sat, 11 Jul 2015 16:31:29 +0530 Subject: made PassphraseDialogActivity compatible with null CryptoInputParcel --- .../keychain/ui/NfcOperationActivity.java | 20 ++++++++++++++++---- .../keychain/ui/PassphraseDialogActivity.java | 5 +++++ .../keychain/ui/base/CryptoOperationHelper.java | 4 ++-- 3 files changed, 23 insertions(+), 6 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index 8802cd621..e9066b76c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -43,11 +43,12 @@ import java.util.Arrays; public class NfcOperationActivity extends BaseNfcActivity { public static final String EXTRA_REQUIRED_INPUT = "required_input"; + public static final String EXTRA_CRYPTO_INPUT = "crypto_input"; // passthrough for OpenPgpService public static final String EXTRA_SERVICE_INTENT = "data"; - public static final String RESULT_DATA = "result_data"; + public static final String RESULT_CRYPTO_INPUT = "result_data"; public ViewAnimator vAnimator; public TextView vErrorText; @@ -67,6 +68,14 @@ public class NfcOperationActivity extends BaseNfcActivity { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + mInputParcel = getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT); + + if (mInputParcel == null) { + // for compatibility when used from OpenPgpService + // (or any place other than CryptoOperationHelper) + mInputParcel = new CryptoInputParcel(mRequiredInput.mSignatureTime); + } + setTitle(R.string.nfc_text); vAnimator = (ViewAnimator) findViewById(R.id.view_animator); @@ -112,8 +121,6 @@ public class NfcOperationActivity extends BaseNfcActivity { @Override protected void doNfcInBackground() throws IOException { - mInputParcel = new CryptoInputParcel(mRequiredInput.mSignatureTime); - switch (mRequiredInput.mType) { case NFC_DECRYPT: { for (int i = 0; i < mRequiredInput.mInputData.length; i++) { @@ -218,11 +225,16 @@ public class NfcOperationActivity extends BaseNfcActivity { @Override protected void onNfcPostExecute() throws IOException { if (mServiceIntent != null) { + // if we're triggered by OpenPgpService CryptoInputParcelCacheService.addCryptoInputParcel(this, mServiceIntent, mInputParcel); + mServiceIntent.putExtra(EXTRA_CRYPTO_INPUT, + getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT)); setResult(RESULT_OK, mServiceIntent); } else { Intent result = new Intent(); - result.putExtra(NfcOperationActivity.RESULT_DATA, mInputParcel); + result.putExtra(RESULT_CRYPTO_INPUT, mInputParcel); + // send back the CryptoInputParcel we receive, to conform with the pattern in + // CryptoOperationHelper setResult(RESULT_OK, result); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index c9f6423d6..d68b39fc1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -95,6 +95,11 @@ public class PassphraseDialogActivity extends FragmentActivity { mCryptoInputParcel = getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT); + if (mCryptoInputParcel == null) { + // not all usages of PassphraseActivity are from CryptoInputOperation + mCryptoInputParcel = new CryptoInputParcel(); + } + // this activity itself has no content view (see manifest) if (getIntent().hasExtra(EXTRA_SUBKEY_ID)) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java index 932b6c007..b33128978 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java @@ -120,13 +120,13 @@ public class CryptoOperationHelper Date: Mon, 13 Jul 2015 03:23:56 +0530 Subject: added revocation tag NO_REASON to all revocations via PgpKeyOperation --- .../java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 7 +++++++ .../sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 565a3bb79..c82cbce8f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -22,6 +22,7 @@ import org.spongycastle.bcpg.PublicKeyAlgorithmTags; import org.spongycastle.bcpg.S2K; import org.spongycastle.bcpg.sig.Features; import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.bcpg.sig.RevocationReasonTags; import org.spongycastle.jce.spec.ElGamalParameterSpec; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPKeyFlags; @@ -1525,6 +1526,9 @@ public class PgpKeyOperation { throws IOException, PGPException, SignatureException { PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator(); + // we use the tag NO_REASON since gnupg does not care about the tag while verifying + // signatures with a revoked key, the warning is the same + subHashedPacketsGen.setRevocationReason(true, RevocationReasonTags.NO_REASON, ""); subHashedPacketsGen.setSignatureCreationTime(true, creationTime); sGen.setHashedSubpackets(subHashedPacketsGen.generate()); sGen.init(PGPSignature.CERTIFICATION_REVOCATION, masterPrivateKey); @@ -1537,6 +1541,9 @@ public class PgpKeyOperation { throws IOException, PGPException, SignatureException { PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator(); + // we use the tag NO_REASON since gnupg does not care about the tag while verifying + // signatures with a revoked key, the warning is the same + subHashedPacketsGen.setRevocationReason(true, RevocationReasonTags.NO_REASON, ""); subHashedPacketsGen.setSignatureCreationTime(true, creationTime); sGen.setHashedSubpackets(subHashedPacketsGen.generate()); // Generate key revocation or subkey revocation, depending on master/subkey-ness diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java index 148ca3346..924d62199 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -20,7 +20,7 @@ package org.sufficientlysecure.keychain.ui; import android.app.Activity; -import android.app.AlertDialog; +import android.support.v7.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; -- cgit v1.2.3 From 771d65476647c4df0d88e95f8df80b201eeb9bf3 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Wed, 15 Jul 2015 07:26:45 +0530 Subject: made mSignatureTime optional in CryptoOperationHelper --- .../keychain/remote/OpenPgpService.java | 32 ++++++++++++++-------- .../keychain/service/input/CryptoInputParcel.java | 32 +++++++++++++++++----- .../keychain/ui/CertifyKeyFragment.java | 4 ++- .../keychain/ui/CreateKeyFinalFragment.java | 4 ++- .../keychain/ui/DeleteKeyDialogActivity.java | 3 +- .../keychain/ui/EditKeyFragment.java | 4 ++- .../keychain/ui/EncryptFilesFragment.java | 10 ++++--- .../keychain/ui/EncryptTextFragment.java | 6 ++-- .../keychain/ui/NfcOperationActivity.java | 9 +++++- .../keychain/ui/PassphraseDialogActivity.java | 7 ++++- .../keychain/operations/CertifyOperationTest.java | 13 +++++---- .../keychain/pgp/PgpEncryptDecryptTest.java | 25 +++++++++++------ .../pgp/UncachedKeyringCanonicalizeTest.java | 2 +- .../keychain/pgp/UncachedKeyringMergeTest.java | 12 ++++---- 14 files changed, 112 insertions(+), 51 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index af99f01c9..2568d68b9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -64,6 +64,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Date; import java.util.HashSet; public class OpenPgpService extends RemoteService { @@ -164,7 +165,9 @@ public class OpenPgpService extends RemoteService { } private static PendingIntent getRequiredInputPendingIntent(Context context, - Intent data, RequiredInputParcel requiredInput) { + Intent data, + RequiredInputParcel requiredInput, + CryptoInputParcel cryptoInput) { switch (requiredInput.mType) { case NFC_MOVE_KEY_TO_CARD: @@ -175,6 +178,7 @@ public class OpenPgpService extends RemoteService { // pass params through to activity that it can be returned again later to repeat pgp operation intent.putExtra(NfcOperationActivity.EXTRA_SERVICE_INTENT, data); intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput); + intent.putExtra(NfcOperationActivity.EXTRA_CRYPTO_INPUT, cryptoInput); return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); } @@ -185,6 +189,7 @@ public class OpenPgpService extends RemoteService { // pass params through to activity that it can be returned again later to repeat pgp operation intent.putExtra(PassphraseDialogActivity.EXTRA_SERVICE_INTENT, data); intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput); + intent.putExtra(PassphraseDialogActivity.EXTRA_CRYPTO_INPUT, cryptoInput); return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); } @@ -279,12 +284,12 @@ public class OpenPgpService extends RemoteService { CryptoInputParcel inputParcel = CryptoInputParcelCacheService.getCryptoInputParcel(this, data); if (inputParcel == null) { - inputParcel = new CryptoInputParcel(); + inputParcel = new CryptoInputParcel(new Date()); } // override passphrase in input parcel if given by API call if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - inputParcel = new CryptoInputParcel(inputParcel.getSignatureTime(), - new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE))); + inputParcel.mPassphrase = + new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)); } // execute PGP operation! @@ -294,7 +299,8 @@ public class OpenPgpService extends RemoteService { if (pgpResult.isPending()) { RequiredInputParcel requiredInput = pgpResult.getRequiredInputParcel(); - PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data, requiredInput); + PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data, + requiredInput, pgpResult.mCryptoInputParcel); // return PendingIntent to be executed by client Intent result = new Intent(); @@ -434,12 +440,12 @@ public class OpenPgpService extends RemoteService { CryptoInputParcel inputParcel = CryptoInputParcelCacheService.getCryptoInputParcel(this, data); if (inputParcel == null) { - inputParcel = new CryptoInputParcel(); + inputParcel = new CryptoInputParcel(new Date()); } // override passphrase in input parcel if given by API call if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - inputParcel = new CryptoInputParcel(inputParcel.getSignatureTime(), - new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE))); + inputParcel.mPassphrase = + new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)); } PgpSignEncryptOperation op = new PgpSignEncryptOperation(this, new ProviderHelper(getContext()), null); @@ -449,7 +455,8 @@ public class OpenPgpService extends RemoteService { if (pgpResult.isPending()) { RequiredInputParcel requiredInput = pgpResult.getRequiredInputParcel(); - PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data, requiredInput); + PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data, + requiredInput, pgpResult.mCryptoInputParcel); // return PendingIntent to be executed by client Intent result = new Intent(); @@ -519,8 +526,8 @@ public class OpenPgpService extends RemoteService { } // override passphrase in input parcel if given by API call if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - cryptoInput = new CryptoInputParcel(cryptoInput.getSignatureTime(), - new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE))); + cryptoInput.mPassphrase = + new Passphrase(data.getCharArrayExtra(OpenPgpApi.EXTRA_PASSPHRASE)); } byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE); @@ -543,7 +550,8 @@ public class OpenPgpService extends RemoteService { if (pgpResult.isPending()) { // prepare and return PendingIntent to be executed by client RequiredInputParcel requiredInput = pgpResult.getRequiredInputParcel(); - PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data, requiredInput); + PendingIntent pIntent = getRequiredInputPendingIntent(getBaseContext(), data, + requiredInput, pgpResult.mCryptoInputParcel); Intent result = new Intent(); result.putExtra(OpenPgpApi.RESULT_INTENT, pIntent); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java index 9ba9601e5..0d8569fe6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java @@ -33,7 +33,9 @@ import java.util.Map; */ public class CryptoInputParcel implements Parcelable { - final Date mSignatureTime; + private Date mSignatureTime; + private boolean mHasSignature; + public Passphrase mPassphrase; // used to supply an explicit proxy to operations that require it // this is not final so it can be added to an existing CryptoInputParcel @@ -48,24 +50,25 @@ public class CryptoInputParcel implements Parcelable { private HashMap mCryptoData = new HashMap<>(); public CryptoInputParcel() { - mSignatureTime = new Date(); + mSignatureTime = null; mPassphrase = null; mCachePassphrase = true; } public CryptoInputParcel(Date signatureTime, Passphrase passphrase) { + mHasSignature = true; mSignatureTime = signatureTime == null ? new Date() : signatureTime; mPassphrase = passphrase; mCachePassphrase = true; } public CryptoInputParcel(Passphrase passphrase) { - mSignatureTime = new Date(); mPassphrase = passphrase; mCachePassphrase = true; } public CryptoInputParcel(Date signatureTime) { + mHasSignature = true; mSignatureTime = signatureTime == null ? new Date() : signatureTime; mPassphrase = null; mCachePassphrase = true; @@ -76,14 +79,22 @@ public class CryptoInputParcel implements Parcelable { mParcelableProxy = parcelableProxy; } - public CryptoInputParcel(boolean cachePassphrase) { - mSignatureTime = new Date(); + public CryptoInputParcel(Date signatureTime, boolean cachePassphrase) { + mHasSignature = true; + mSignatureTime = signatureTime == null ? new Date() : signatureTime; mPassphrase = null; mCachePassphrase = cachePassphrase; } + public CryptoInputParcel(boolean cachePassphrase) { + mCachePassphrase = cachePassphrase; + } + protected CryptoInputParcel(Parcel source) { - mSignatureTime = new Date(source.readLong()); + mHasSignature = source.readByte() != 0; + if (mHasSignature) { + mSignatureTime = new Date(source.readLong()); + } mPassphrase = source.readParcelable(getClass().getClassLoader()); mParcelableProxy = source.readParcelable(getClass().getClassLoader()); mCachePassphrase = source.readByte() != 0; @@ -107,7 +118,10 @@ public class CryptoInputParcel implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(mSignatureTime.getTime()); + dest.writeByte((byte) (mHasSignature ? 1 : 0)); + if (mHasSignature) { + dest.writeLong(mSignatureTime.getTime()); + } dest.writeParcelable(mPassphrase, 0); dest.writeParcelable(mParcelableProxy, 0); dest.writeByte((byte) (mCachePassphrase ? 1 : 0)); @@ -123,6 +137,10 @@ public class CryptoInputParcel implements Parcelable { mParcelableProxy = parcelableProxy; } + public void addSignatureTime(Date signatureTime) { + mSignatureTime = signatureTime; + } + public void addCryptoData(byte[] hash, byte[] signedHash) { mCryptoData.put(ByteBuffer.wrap(hash), signedHash); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index 467eab785..65baf0593 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -49,6 +49,7 @@ import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter; import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment; import org.sufficientlysecure.keychain.ui.util.Notify; @@ -57,6 +58,7 @@ import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; import java.util.ArrayList; +import java.util.Date; public class CertifyKeyFragment extends CachingCryptoOperationFragment @@ -165,7 +167,7 @@ public class CertifyKeyFragment Notify.create(getActivity(), getString(R.string.select_key_to_certify), Notify.Style.ERROR).show(); } else { - cryptoOperation(); + cryptoOperation(new CryptoInputParcel(new Date())); } } }); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java index 65bdca5c4..739eb3e35 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -18,6 +18,7 @@ package org.sufficientlysecure.keychain.ui; +import java.util.Date; import java.util.Iterator; import android.app.Activity; @@ -47,6 +48,7 @@ import org.sufficientlysecure.keychain.service.ExportKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.util.Log; @@ -393,7 +395,7 @@ public class CreateKeyFinalFragment extends Fragment { mMoveToCardOpHelper = new CryptoOperationHelper<>(2, this, callback, R.string.progress_modify); - mMoveToCardOpHelper.cryptoOperation(); + mMoveToCardOpHelper.cryptoOperation(new CryptoInputParcel(new Date())); } private void uploadKey(final EditKeyResult saveKeyResult) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java index 924d62199..1b4083a94 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -50,6 +50,7 @@ import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; import org.sufficientlysecure.keychain.util.Log; +import java.util.Date; import java.util.HashMap; public class DeleteKeyDialogActivity extends FragmentActivity { @@ -134,7 +135,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { } private void startRevocationOperation() { - mRevokeOpHelper.cryptoOperation(new CryptoInputParcel(false)); + mRevokeOpHelper.cryptoOperation(new CryptoInputParcel(new Date(), false)); } private void startDeletionOperation() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index 4e9c5a836..4769e68d8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -68,6 +68,8 @@ import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; +import java.util.Date; + public class EditKeyFragment extends QueueingCryptoOperationFragment implements LoaderManager.LoaderCallbacks { @@ -151,7 +153,7 @@ public class EditKeyFragment extends QueueingCryptoOperationFragment * For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf + * NOTE: If no CryptoInputParcel is passed via EXTRA_CRYPTO_INPUT, the CryptoInputParcel is created + * internally and is NOT meant to be used by signing operations before adding signature time */ public class NfcOperationActivity extends BaseNfcActivity { @@ -73,7 +76,8 @@ public class NfcOperationActivity extends BaseNfcActivity { if (mInputParcel == null) { // for compatibility when used from OpenPgpService // (or any place other than CryptoOperationHelper) - mInputParcel = new CryptoInputParcel(mRequiredInput.mSignatureTime); + // NOTE: This CryptoInputParcel cannot be used for signing without adding signature time + mInputParcel = new CryptoInputParcel(); } setTitle(R.string.nfc_text); @@ -131,6 +135,9 @@ public class NfcOperationActivity extends BaseNfcActivity { break; } case NFC_SIGN: { + if (mInputParcel.getSignatureTime() == null) { + mInputParcel.addSignatureTime(new Date()); + } for (int i = 0; i < mRequiredInput.mInputData.length; i++) { byte[] hash = mRequiredInput.mInputData[i]; int algo = mRequiredInput.mSignAlgos[i]; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index d68b39fc1..8b482584d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -66,6 +66,8 @@ import org.sufficientlysecure.keychain.util.Preferences; /** * We can not directly create a dialog on the application context. * This activity encapsulates a DialogFragment to emulate a dialog. + * NOTE: If no CryptoInputParcel is passed via EXTRA_CRYPTO_INPUT, the CryptoInputParcel is created + * internally and is NOT meant to be used by signing operations before adding a signature time */ public class PassphraseDialogActivity extends FragmentActivity { public static final String RESULT_CRYPTO_INPUT = "result_data"; @@ -97,6 +99,8 @@ public class PassphraseDialogActivity extends FragmentActivity { if (mCryptoInputParcel == null) { // not all usages of PassphraseActivity are from CryptoInputOperation + // NOTE: This CryptoInputParcel cannot be used for signing operations without setting + // signature time mCryptoInputParcel = new CryptoInputParcel(); } @@ -123,7 +127,8 @@ public class PassphraseDialogActivity extends FragmentActivity { SecretKeyType.PASSPHRASE_EMPTY) { // also return passphrase back to activity Intent returnIntent = new Intent(); - returnIntent.putExtra(RESULT_CRYPTO_INPUT, new CryptoInputParcel(new Passphrase(""))); + mCryptoInputParcel.mPassphrase = new Passphrase(""); + returnIntent.putExtra(RESULT_CRYPTO_INPUT, mCryptoInputParcel); setResult(RESULT_OK, returnIntent); finish(); return; diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java index 6984f126e..472e4507a 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java @@ -52,6 +52,7 @@ import org.sufficientlysecure.keychain.util.TestingUtils; import java.io.PrintStream; import java.security.Security; import java.util.ArrayList; +import java.util.Date; import java.util.Random; @RunWith(RobolectricGradleTestRunner.class) @@ -158,7 +159,7 @@ public class CertifyOperationTest { CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId()); actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(), mStaticRing2.getPublicKey().getUnorderedUserIds())); - CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1)); + CertifyResult result = op.execute(actions, new CryptoInputParcel(new Date(), mKeyPhrase1)); Assert.assertTrue("certification must succeed", result.success()); @@ -186,7 +187,7 @@ public class CertifyOperationTest { CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId()); actions.add(new CertifyAction(mStaticRing2.getMasterKeyId(), null, mStaticRing2.getPublicKey().getUnorderedUserAttributes())); - CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1)); + CertifyResult result = op.execute(actions, new CryptoInputParcel(new Date(), mKeyPhrase1)); Assert.assertTrue("certification must succeed", result.success()); @@ -209,7 +210,7 @@ public class CertifyOperationTest { actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(), mStaticRing2.getPublicKey().getUnorderedUserIds())); - CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1)); + CertifyResult result = op.execute(actions, new CryptoInputParcel(new Date(), mKeyPhrase1)); Assert.assertFalse("certification with itself must fail!", result.success()); Assert.assertTrue("error msg must be about self certification", @@ -228,7 +229,8 @@ public class CertifyOperationTest { uids.add("nonexistent"); actions.add(new CertifyAction(1234L, uids)); - CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1)); + CertifyResult result = op.execute(actions, new CryptoInputParcel(new Date(), + mKeyPhrase1)); Assert.assertFalse("certification of nonexistent key must fail", result.success()); Assert.assertTrue("must contain error msg about not found", @@ -240,7 +242,8 @@ public class CertifyOperationTest { actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(), mStaticRing2.getPublicKey().getUnorderedUserIds())); - CertifyResult result = op.execute(actions, new CryptoInputParcel(mKeyPhrase1)); + CertifyResult result = op.execute(actions, new CryptoInputParcel(new Date(), + mKeyPhrase1)); Assert.assertFalse("certification of nonexistent key must fail", result.success()); Assert.assertTrue("must contain error msg about not found", diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java index 39230df0e..edd7880fc 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java @@ -25,6 +25,7 @@ import java.security.Security; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; +import java.util.Date; import org.junit.Assert; import org.junit.Before; @@ -160,7 +161,8 @@ public class PgpEncryptDecryptTest { b.setSymmetricPassphrase(mPassphrase); b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128); - PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(), data, out); + PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(new Date()), + data, out); Assert.assertTrue("encryption must succeed", result.success()); @@ -269,7 +271,8 @@ public class PgpEncryptDecryptTest { input.setEncryptionMasterKeyIds(new long[] { mStaticRing1.getMasterKeyId() }); input.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128); - PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(), data, out); + PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(new Date()), + data, out); Assert.assertTrue("encryption must succeed", result.success()); ciphertext = out.toByteArray(); @@ -359,7 +362,8 @@ public class PgpEncryptDecryptTest { input.setEncryptionMasterKeyIds(new long[] { mStaticRing1.getMasterKeyId() }); input.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128); - PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(), data, out); + PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(new Date()), + data, out); Assert.assertTrue("encryption must succeed", result.success()); ciphertext = out.toByteArray(); @@ -393,7 +397,8 @@ public class PgpEncryptDecryptTest { SaveKeyringParcel parcel = new SaveKeyringParcel(mStaticRing1.getMasterKeyId(), mStaticRing1.getFingerprint()); parcel.mRevokeSubKeys.add(KeyringTestingHelper.getSubkeyId(mStaticRing1, 2)); UncachedKeyRing modified = PgpKeyOperationTest.applyModificationWithChecks(parcel, mStaticRing1, - new ArrayList(), new ArrayList(), new CryptoInputParcel(mKeyPhrase1)); + new ArrayList(), new ArrayList(), + new CryptoInputParcel(new Date(), mKeyPhrase1)); ProviderHelper providerHelper = new ProviderHelper(RuntimeEnvironment.application); providerHelper.saveSecretKeyRing(modified, new ProgressScaler()); @@ -413,7 +418,8 @@ public class PgpEncryptDecryptTest { input.setEncryptionMasterKeyIds(new long[] { mStaticRing1.getMasterKeyId() }); input.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128); - PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(), data, out); + PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(new Date()), + data, out); Assert.assertTrue("encryption must succeed", result.success()); ciphertext = out.toByteArray(); @@ -457,7 +463,8 @@ public class PgpEncryptDecryptTest { }); b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128); - PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(), data, out); + PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(new Date()), + data, out); Assert.assertTrue("encryption must succeed", result.success()); ciphertext = out.toByteArray(); @@ -575,7 +582,8 @@ public class PgpEncryptDecryptTest { b.setSignatureSubKeyId(KeyringTestingHelper.getSubkeyId(mStaticRing1, 1)); b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128); - PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(mKeyPhrase1), data, out); + PgpSignEncryptResult result = op.execute(b, + new CryptoInputParcel(new Date(), mKeyPhrase1), data, out); Assert.assertTrue("encryption must succeed", result.success()); ciphertext = out.toByteArray(); @@ -655,7 +663,8 @@ public class PgpEncryptDecryptTest { // this only works with ascii armored output! b.setEnableAsciiArmorOutput(true); b.setCharset("iso-2022-jp"); - PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(), data, out); + PgpSignEncryptResult result = op.execute(b, new CryptoInputParcel(new Date()), + data, out); Assert.assertTrue("encryption must succeed", result.success()); ciphertext = out.toByteArray(); diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java index ad4c1fb75..a0f3b6be6 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java @@ -554,7 +554,7 @@ public class UncachedKeyringCanonicalizeTest { CanonicalizedSecretKey masterSecretKey = canonicalized.getSecretKey(); masterSecretKey.unlock(new Passphrase()); PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey(); - CryptoInputParcel cryptoInput = new CryptoInputParcel(); + CryptoInputParcel cryptoInput = new CryptoInputParcel(new Date()); PGPSignature cert = PgpKeyOperation.generateSubkeyBindingSignature( PgpKeyOperation.getSignatureGenerator(masterSecretKey.getSecretKey(), cryptoInput), cryptoInput.getSignatureTime(), diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java index cc5c487bd..6755431d0 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java @@ -194,11 +194,11 @@ public class UncachedKeyringMergeTest { parcel.reset(); parcel.mAddUserIds.add("flim"); - modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing(); + modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing(); parcel.reset(); parcel.mAddUserIds.add("flam"); - modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing(); + modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing(); } { // merge A into base @@ -235,8 +235,8 @@ public class UncachedKeyringMergeTest { parcel.reset(); parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd( Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L)); - modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing(); - modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing(); + modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing(); + modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing(); subKeyIdA = KeyringTestingHelper.getSubkeyId(modifiedA, 2); subKeyIdB = KeyringTestingHelper.getSubkeyId(modifiedB, 2); @@ -277,7 +277,7 @@ public class UncachedKeyringMergeTest { parcel.mRevokeSubKeys.add(KeyringTestingHelper.getSubkeyId(ringA, 1)); CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing( ringA.getEncoded(), false, 0); - modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing(); + modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing(); } { @@ -376,7 +376,7 @@ public class UncachedKeyringMergeTest { CanonicalizedSecretKeyRing secretRing = new CanonicalizedSecretKeyRing( ringA.getEncoded(), false, 0); - modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Passphrase()), parcel).getRing(); + modified = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing(); } { -- cgit v1.2.3 From fe0b083bc5fdcd3cd4543945ef22bcec7a2876f4 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Wed, 15 Jul 2015 20:16:07 +0530 Subject: fixed multi-deletion bug, moved logic into DeleteKeyDialogActivity --- .../keychain/operations/results/DeleteResult.java | 5 +++- .../operations/results/OperationResult.java | 2 +- .../keychain/ui/DeleteKeyDialogActivity.java | 29 +++++++++++++--------- .../keychain/ui/KeyListFragment.java | 7 ------ 4 files changed, 22 insertions(+), 21 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java index c7c48ed56..1a8f10d4f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java @@ -125,7 +125,10 @@ public class DeleteResult extends InputPendingResult { } else { duration = 0; style = Style.ERROR; - if (mFail == 0) { + if (mLog.getLast().mType == LogType.MSG_DEL_ERROR_MULTI_SECRET) { + str = activity.getString(R.string.secret_cannot_multiple); + } + else if (mFail == 0) { str = activity.getString(R.string.delete_nothing); } else { str = activity.getResources().getQuantityString(R.plurals.delete_fail, mFail); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index d4b3c433f..04013e9ed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -754,7 +754,7 @@ public abstract class OperationResult implements Parcelable { MSG_GET_QUERY_FAILED(LogLevel.ERROR, R.string.msg_download_query_failed), MSG_DEL_ERROR_EMPTY (LogLevel.ERROR, R.string.msg_del_error_empty), - MSG_DEL_ERROR_MULTI_SECRET (LogLevel.DEBUG, R.string.msg_del_error_multi_secret), + MSG_DEL_ERROR_MULTI_SECRET (LogLevel.ERROR, R.string.msg_del_error_multi_secret), MSG_DEL (LogLevel.START, R.plurals.msg_del), MSG_DEL_KEY (LogLevel.DEBUG, R.string.msg_del_key), MSG_DEL_KEY_FAIL (LogLevel.WARN, R.string.msg_del_key_fail), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java index 1b4083a94..4c1dbd1ee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -48,6 +48,7 @@ import org.sufficientlysecure.keychain.service.RevokeKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; +import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; import java.util.Date; @@ -62,6 +63,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { private CryptoOperationHelper mRevokeOpHelper; private long[] mMasterKeyIds; + private boolean mHasSecret; @Override protected void onCreate(Bundle savedInstanceState) { @@ -74,14 +76,17 @@ public class DeleteKeyDialogActivity extends FragmentActivity { getRevocationCallback(), R.string.progress_revoking_uploading); mMasterKeyIds = getIntent().getLongArrayExtra(EXTRA_DELETE_MASTER_KEY_IDS); - boolean hasSecret = getIntent().getBooleanExtra(EXTRA_HAS_SECRET, false); - - if (mMasterKeyIds.length > 1 && hasSecret) { - throw new AssertionError("Secret keys can be deleted only one at a time!" + - " Should be checked before reaching DeleteKeyDialogActivity."); + mHasSecret = getIntent().getBooleanExtra(EXTRA_HAS_SECRET, false); + + if (mMasterKeyIds.length > 1 && mHasSecret) { + // secret keys can only be deleted individually + OperationResult.OperationLog log = new OperationResult.OperationLog(); + log.add(OperationResult.LogType.MSG_DEL_ERROR_MULTI_SECRET, 0); + returnResult(new DeleteResult(OperationResult.RESULT_ERROR, log, 0, + mMasterKeyIds.length)); } - if (mMasterKeyIds.length == 1 && hasSecret) { + if (mMasterKeyIds.length == 1 && mHasSecret) { // if mMasterKeyIds.length == 0 we let the DeleteOperation respond try { HashMap data = new ProviderHelper(this).getUnifiedData( @@ -122,7 +127,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { private void showNormalDeleteDialog() { DeleteKeyDialogFragment deleteKeyDialogFragment - = DeleteKeyDialogFragment.newInstance(mMasterKeyIds); + = DeleteKeyDialogFragment.newInstance(mMasterKeyIds, mHasSecret); deleteKeyDialogFragment.show(getSupportFragmentManager(), "deleteKeyDialog"); @@ -179,7 +184,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { return new CryptoOperationHelper.Callback() { @Override public DeleteKeyringParcel createOperationInput() { - return new DeleteKeyringParcel(mMasterKeyIds, true); + return new DeleteKeyringParcel(mMasterKeyIds, mHasSecret); } @Override @@ -221,6 +226,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { public static class DeleteKeyDialogFragment extends DialogFragment { private static final String ARG_DELETE_MASTER_KEY_IDS = "delete_master_key_ids"; + private static final String ARG_HAS_SECRET = "has_secret"; private TextView mMainMessage; private View mInflateView; @@ -228,11 +234,12 @@ public class DeleteKeyDialogActivity extends FragmentActivity { /** * Creates new instance of this delete file dialog fragment */ - public static DeleteKeyDialogFragment newInstance(long[] masterKeyIds) { + public static DeleteKeyDialogFragment newInstance(long[] masterKeyIds, boolean hasSecret) { DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment(); Bundle args = new Bundle(); args.putLongArray(ARG_DELETE_MASTER_KEY_IDS, masterKeyIds); + args.putBoolean(ARG_HAS_SECRET, hasSecret); frag.setArguments(args); @@ -245,6 +252,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { final FragmentActivity activity = getActivity(); final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS); + final boolean hasSecret = getArguments().getBoolean(ARG_HAS_SECRET); ContextThemeWrapper theme = new ContextThemeWrapper(activity, R.style.Theme_AppCompat_Light_Dialog); @@ -258,8 +266,6 @@ public class DeleteKeyDialogActivity extends FragmentActivity { mMainMessage = (TextView) mInflateView.findViewById(R.id.mainMessage); - final boolean hasSecret; - // If only a single key has been selected if (masterKeyIds.length == 1) { long masterKeyId = masterKeyIds[0]; @@ -281,7 +287,6 @@ public class DeleteKeyDialogActivity extends FragmentActivity { } else { name = getString(R.string.user_id_no_name); } - hasSecret = ((Long) data.get(KeychainContract.KeyRings.HAS_ANY_SECRET)) == 1; if (hasSecret) { // show title only for secret key deletions, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index a42dfef23..95e047b0f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -352,13 +352,6 @@ public class KeyListFragment extends LoaderFragment * @param hasSecret must contain whether the list of masterKeyIds contains a secret key or not */ public void showDeleteKeyDialog(long[] masterKeyIds, boolean hasSecret) { - // Can only work on singular secret keys - if (hasSecret && masterKeyIds.length > 1) { - Notify.create(getActivity(), R.string.secret_cannot_multiple, - Notify.Style.ERROR).show(); - return; - } - Intent intent = new Intent(getActivity(), DeleteKeyDialogActivity.class); intent.putExtra(DeleteKeyDialogActivity.EXTRA_DELETE_MASTER_KEY_IDS, masterKeyIds); intent.putExtra(DeleteKeyDialogActivity.EXTRA_HAS_SECRET, hasSecret); -- cgit v1.2.3