aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2015-07-08 03:12:24 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2015-07-08 03:12:24 +0200
commit4837d4cc5c86a5f5f18cb86300f165cf1b37f4d2 (patch)
treefeeaaa654f24df80453e69a43cff84770c95fd27 /OpenKeychain
parent15cee8e7e995afe1c435004c3abba521439e4e0b (diff)
parentaf546ae10190ac076cd7b091cd064fb8a5c03519 (diff)
downloadopen-keychain-4837d4cc5c86a5f5f18cb86300f165cf1b37f4d2.tar.gz
open-keychain-4837d4cc5c86a5f5f18cb86300f165cf1b37f4d2.tar.bz2
open-keychain-4837d4cc5c86a5f5f18cb86300f165cf1b37f4d2.zip
Merge branch 'master' of github.com:open-keychain/open-keychain
Diffstat (limited to 'OpenKeychain')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java15
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java77
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java16
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java13
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java58
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java17
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java15
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java106
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java15
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/QueueingCryptoOperationFragment.java92
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java20
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml5
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java34
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java5
28 files changed, 357 insertions, 220 deletions
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 318eee6ba..d0377cc24 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
@@ -29,6 +29,7 @@ import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
+import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface;
import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation;
import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation.PgpCertifyResult;
import org.sufficientlysecure.keychain.pgp.Progressable;
@@ -90,14 +91,21 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
case PIN:
case PATTERN:
case PASSPHRASE:
- if (!cryptoInput.hasPassphrase()) {
+ passphrase = cryptoInput.getPassphrase();
+ if (passphrase == null) {
+ try {
+ passphrase = getCachedPassphrase(certificationKey.getKeyId(), certificationKey.getKeyId());
+ } catch (PassphraseCacheInterface.NoSecretKeyException ignored) {
+ // treat as a cache miss for error handling purposes
+ }
+ }
+
+ if (passphrase == null) {
return new CertifyResult(log,
RequiredInputParcel.createRequiredSignPassphrase(
certificationKey.getKeyId(), certificationKey.getKeyId(), null)
);
}
- // certification is always with the master key id, so use that one
- passphrase = cryptoInput.getPassphrase();
break;
case PASSPHRASE_EMPTY:
@@ -105,6 +113,7 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
break;
case DIVERT_TO_CARD:
+ // the unlock operation will succeed for passphrase == null in a divertToCard key
passphrase = null;
break;
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 5ae068b35..9da3b94af 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
@@ -482,6 +482,7 @@ public abstract class OperationResult implements Parcelable {
// secret key modify
MSG_MF (LogLevel.START, R.string.msg_mr),
MSG_MF_DIVERT (LogLevel.DEBUG, R.string.msg_mf_divert),
+ MSG_MF_ERROR_DIVERT_NEWSUB (LogLevel.ERROR, R.string.msg_mf_error_divert_newsub),
MSG_MF_ERROR_DIVERT_SERIAL (LogLevel.ERROR, R.string.msg_mf_error_divert_serial),
MSG_MF_ERROR_ENCODE (LogLevel.ERROR, R.string.msg_mf_error_encode),
MSG_MF_ERROR_FINGERPRINT (LogLevel.ERROR, R.string.msg_mf_error_fingerprint),
@@ -499,6 +500,7 @@ public abstract class OperationResult implements Parcelable {
MSG_MF_ERROR_RESTRICTED(LogLevel.ERROR, R.string.msg_mf_error_restricted),
MSG_MF_ERROR_REVOKED_PRIMARY (LogLevel.ERROR, R.string.msg_mf_error_revoked_primary),
MSG_MF_ERROR_SIG (LogLevel.ERROR, R.string.msg_mf_error_sig),
+ MSG_MF_ERROR_SUB_STRIPPED(LogLevel.ERROR, R.string.msg_mf_error_sub_stripped),
MSG_MF_ERROR_SUBKEY_MISSING(LogLevel.ERROR, R.string.msg_mf_error_subkey_missing),
MSG_MF_ERROR_CONFLICTING_NFC_COMMANDS(LogLevel.ERROR, R.string.msg_mf_error_conflicting_nfc_commands),
MSG_MF_ERROR_DUPLICATE_KEYTOCARD_FOR_SLOT(LogLevel.ERROR, R.string.msg_mf_error_duplicate_keytocard_for_slot),
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 8445272fc..5eaa03394 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -897,18 +897,35 @@ public class PgpKeyOperation {
pKey = PGPPublicKey.removeCertification(pKey, sig);
}
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- cryptoInput.getPassphrase().getCharArray());
- PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
- PGPSignature sig = generateSubkeyBindingSignature(
- getSignatureGenerator(masterSecretKey, cryptoInput),
- cryptoInput.getSignatureTime(),
- masterPublicKey, masterPrivateKey, subPrivateKey, pKey, flags, expiry);
+ PGPPrivateKey subPrivateKey;
+ if (!isDivertToCard(sKey)) {
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
+ cryptoInput.getPassphrase().getCharArray());
+ subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
+ // super special case: subkey is allowed to sign, but isn't available
+ if (subPrivateKey == null) {
+ log.add(LogType.MSG_MF_ERROR_SUB_STRIPPED,
+ indent + 1, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId));
+ return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
+ }
+ } else {
+ subPrivateKey = null;
+ }
+ try {
+ PGPSignature sig = generateSubkeyBindingSignature(
+ getSignatureGenerator(masterSecretKey, cryptoInput),
+ cryptoInput.getSignatureTime(), masterPublicKey, masterPrivateKey,
+ getSignatureGenerator(sKey, cryptoInput), subPrivateKey,
+ pKey, flags, expiry);
+
+ // generate and add new signature
+ pKey = PGPPublicKey.addCertification(pKey, sig);
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
+ } catch (NfcInteractionNeeded e) {
+ nfcSignOps.addHash(e.hashToSign, e.hashAlgo);
+ }
- // generate and add new signature
- pKey = PGPPublicKey.addCertification(pKey, sig);
- sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
}
subProgressPop();
@@ -959,6 +976,11 @@ public class PgpKeyOperation {
log.add(LogType.MSG_MF_SUBKEY_NEW, indent,
KeyFormattingUtils.getAlgorithmInfo(add.mAlgorithm, add.mKeySize, add.mCurve) );
+ if (isDivertToCard(masterSecretKey)) {
+ log.add(LogType.MSG_MF_ERROR_DIVERT_NEWSUB, indent +1);
+ return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
+ }
+
if (add.mExpiry == null) {
log.add(LogType.MSG_MF_ERROR_NULL_EXPIRY, indent +1);
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
@@ -987,7 +1009,8 @@ public class PgpKeyOperation {
PGPSignature cert = generateSubkeyBindingSignature(
getSignatureGenerator(masterSecretKey, cryptoInput),
cryptoInput.getSignatureTime(),
- masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
+ masterPublicKey, masterPrivateKey,
+ getSignatureGenerator(pKey, cryptoInput, false), keyPair.getPrivateKey(), pKey,
add.mFlags, add.mExpiry);
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
} catch (NfcInteractionNeeded e) {
@@ -1402,22 +1425,27 @@ public class PgpKeyOperation {
static PGPSignatureGenerator getSignatureGenerator(
PGPSecretKey secretKey, CryptoInputParcel cryptoInput) {
- PGPContentSignerBuilder builder;
-
S2K s2k = secretKey.getS2K();
- if (s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K
- && s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD) {
+ boolean isDivertToCard = s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K
+ && s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD;
+
+ return getSignatureGenerator(secretKey.getPublicKey(), cryptoInput, isDivertToCard);
+ }
+
+ static PGPSignatureGenerator getSignatureGenerator(
+ PGPPublicKey pKey, CryptoInputParcel cryptoInput, boolean divertToCard) {
+
+ PGPContentSignerBuilder builder;
+ if (divertToCard) {
// use synchronous "NFC based" SignerBuilder
builder = new NfcSyncPGPContentSignerBuilder(
- secretKey.getPublicKey().getAlgorithm(),
- PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO,
- secretKey.getKeyID(), cryptoInput.getCryptoData())
+ pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO,
+ pKey.getKeyID(), cryptoInput.getCryptoData())
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
} else {
// content signer based on signing key algorithm and chosen hash algorithm
builder = new JcaPGPContentSignerBuilder(
- secretKey.getPublicKey().getAlgorithm(),
- PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
+ pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
}
@@ -1524,7 +1552,8 @@ public class PgpKeyOperation {
static PGPSignature generateSubkeyBindingSignature(
PGPSignatureGenerator sGen, Date creationTime,
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
- PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, long expiry)
+ PGPSignatureGenerator subSigGen, PGPPrivateKey subPrivateKey, PGPPublicKey pKey,
+ int flags, long expiry)
throws IOException, PGPException, SignatureException {
PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
@@ -1534,10 +1563,6 @@ public class PgpKeyOperation {
// cross-certify signing keys
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
subHashedPacketsGen.setSignatureCreationTime(false, creationTime);
- PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
- pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- PGPSignatureGenerator subSigGen = new PGPSignatureGenerator(signerBuilder);
subSigGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
subSigGen.setHashedSubpackets(subHashedPacketsGen.generate());
PGPSignature certification = subSigGen.generateCertification(masterPublicKey, pKey);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index 3346926ec..92ad7372a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -53,7 +53,7 @@ import java.io.IOException;
*/
public class KeychainDatabase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "openkeychain.db";
- private static final int DATABASE_VERSION = 10;
+ private static final int DATABASE_VERSION = 11;
static Boolean apgHack = false;
private Context mContext;
@@ -274,6 +274,12 @@ public class KeychainDatabase extends SQLiteOpenHelper {
db.execSQL(CREATE_CERTS);
case 10:
// do nothing here, just consolidate
+ case 11:
+ db.execSQL("DELETE FROM api_accounts WHERE key_id BETWEEN 0 AND 3");
+ if (oldVersion == 10) {
+ // no consolidate if we are updating from 10, we're just here for the api_accounts fix
+ return;
+ }
}
@@ -297,10 +303,11 @@ public class KeychainDatabase extends SQLiteOpenHelper {
// It's the Java way =(
String[] dbs = context.databaseList();
for (String db : dbs) {
- if (db.equals("apg.db")) {
+ if ("apg.db".equals(db)) {
hasApgDb = true;
- } else if (db.equals("apg_old.db")) {
+ } else if ("apg_old.db".equals(db)) {
Log.d(Constants.TAG, "Found apg_old.db, delete it!");
+ // noinspection ResultOfMethodCallIgnored - if it doesn't happen, it doesn't happen.
context.getDatabasePath("apg_old.db").delete();
}
}
@@ -384,7 +391,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
}
}
- // delete old database
+ // noinspection ResultOfMethodCallIgnored - not much we can do if this doesn't work
context.getDatabasePath("apg.db").delete();
}
@@ -416,6 +423,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
} else {
in = context.getDatabasePath(DATABASE_NAME);
out = context.getDatabasePath("debug_backup.db");
+ // noinspection ResultOfMethodCallIgnored - this is a pure debug feature, anyways
out.createNewFile();
}
if (!in.canRead()) {
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 ab631c6fe..467eab785 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java
@@ -324,16 +324,15 @@ public class CertifyKeyFragment
}
@Override
- public void onCryptoOperationSuccess(CertifyResult result) {
+ public void onQueuedOperationSuccess(CertifyResult result) {
+ // protected by Queueing*Fragment
+ Activity activity = getActivity();
+
Intent intent = new Intent();
intent.putExtra(CertifyResult.EXTRA_RESULT, result);
- getActivity().setResult(Activity.RESULT_OK, intent);
- getActivity().finish();
- }
+ activity.setResult(Activity.RESULT_OK, intent);
+ activity.finish();
- @Override
- public void onCryptoOperationCancelled() {
- super.onCryptoOperationCancelled();
}
}
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 a997dc545..6e41e97a8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
@@ -225,6 +225,33 @@ public class CreateKeyFinalFragment extends Fragment {
}
}
}
+
+ // handle queued actions
+
+ if (mQueuedFinishResult != null) {
+ finishWithResult(mQueuedFinishResult);
+ return;
+ }
+
+ if (mQueuedDisplayResult != null) {
+ try {
+ displayResult(mQueuedDisplayResult);
+ } finally {
+ // clear after operation, note that this may drop the operation if it didn't
+ // work when called from here!
+ mQueuedDisplayResult = null;
+ }
+ }
+
+ if (mQueuedSaveKeyResult != null) {
+ try {
+ uploadKey(mQueuedSaveKeyResult);
+ } finally {
+ // see above
+ mQueuedSaveKeyResult = null;
+ }
+ }
+
}
private void createKey() {
@@ -433,35 +460,4 @@ public class CreateKeyFinalFragment extends Fragment {
activity.finish();
}
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- // there may be queued actions from when we weren't attached to an activity!
-
- if (mQueuedFinishResult != null) {
- finishWithResult(mQueuedFinishResult);
- return;
- }
-
- if (mQueuedDisplayResult != null) {
- try {
- displayResult(mQueuedDisplayResult);
- } finally {
- // clear after operation, note that this may drop the operation if it didn't
- // work when called from here!
- mQueuedDisplayResult = null;
- }
- }
-
- if (mQueuedSaveKeyResult != null) {
- try {
- uploadKey(mQueuedSaveKeyResult);
- } finally {
- // see above
- mQueuedSaveKeyResult = null;
- }
- }
- }
-
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java
index 9e3dce28f..e0adf0b93 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java
@@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui;
+
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -39,7 +40,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment;
-import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
+import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.ParcelableProxy;
import org.sufficientlysecure.keychain.util.Preferences;
@@ -47,7 +48,7 @@ import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
public class CreateYubiKeyImportFragment
- extends CryptoOperationFragment<ImportKeyringParcel, ImportKeyResult>
+ extends QueueingCryptoOperationFragment<ImportKeyringParcel, ImportKeyResult>
implements NfcListenerFragment {
private static final String ARG_FINGERPRINT = "fingerprint";
@@ -246,14 +247,17 @@ public class CreateYubiKeyImportFragment
}
@Override
- public void onCryptoOperationSuccess(ImportKeyResult result) {
+ public void onQueuedOperationSuccess(ImportKeyResult result) {
long[] masterKeyIds = result.getImportedMasterKeyIds();
if (masterKeyIds.length == 0) {
super.onCryptoOperationError(result);
return;
}
- Intent intent = new Intent(getActivity(), ViewKeyActivity.class);
+ // null-protected from Queueing*Fragment
+ Activity activity = getActivity();
+
+ Intent intent = new Intent(activity, ViewKeyActivity.class);
// use the imported masterKeyId, not the one from the yubikey, because
// that one might* just have been a subkey of the imported key
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyIds[0]));
@@ -262,6 +266,6 @@ public class CreateYubiKeyImportFragment
intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
startActivity(intent);
- getActivity().finish();
+ activity.finish();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
index 04f54f151..2f75e4a9c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
@@ -49,13 +49,7 @@ public class DecryptActivity extends BaseActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setFullScreenDialogClose(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setResult(Activity.RESULT_CANCELED);
- finish();
- }
- }, false);
+ setFullScreenDialogClose(Activity.RESULT_CANCELED, false);
// Handle intent actions
handleActions(savedInstanceState, getIntent());
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java
index da6dfcbd0..b38968753 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java
@@ -66,10 +66,10 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
// this import NEEDS to be above the ViewModel one, or it won't compile! (as of 06/06/15)
+import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.StatusHolder;
import org.sufficientlysecure.keychain.ui.DecryptListFragment.DecryptFilesAdapter.ViewModel;
import org.sufficientlysecure.keychain.ui.adapter.SpacesItemDecoration;
-import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify;
@@ -80,7 +80,7 @@ import org.sufficientlysecure.keychain.util.ParcelableHashMap;
public class DecryptListFragment
- extends CryptoOperationFragment<PgpDecryptVerifyInputParcel,DecryptVerifyResult>
+ extends QueueingCryptoOperationFragment<PgpDecryptVerifyInputParcel,DecryptVerifyResult>
implements OnMenuItemClickListener {
public static final String ARG_INPUT_URIS = "input_uris";
@@ -195,15 +195,6 @@ public class DecryptListFragment
cryptoOperation();
}
- private String removeEncryptedAppend(String name) {
- if (name.endsWith(Constants.FILE_EXTENSION_ASC)
- || name.endsWith(Constants.FILE_EXTENSION_PGP_MAIN)
- || name.endsWith(Constants.FILE_EXTENSION_PGP_ALTERNATE)) {
- return name.substring(0, name.length() - 4);
- }
- return name;
- }
-
private void askForOutputFilename(Uri inputUri, String originalFilename, String mimeType) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
File file = new File(inputUri.getPath());
@@ -257,7 +248,7 @@ public class DecryptListFragment
return true;
}
@Override
- public void onCryptoOperationError(DecryptVerifyResult result) {
+ public void onQueuedOperationError(DecryptVerifyResult result) {
final Uri uri = mCurrentInputUri;
mCurrentInputUri = null;
@@ -267,7 +258,7 @@ public class DecryptListFragment
}
@Override
- public void onCryptoOperationSuccess(DecryptVerifyResult result) {
+ public void onQueuedOperationSuccess(DecryptVerifyResult result) {
Uri uri = mCurrentInputUri;
mCurrentInputUri = null;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java
index be21cdde1..3c8e972b9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java
@@ -41,13 +41,7 @@ public class DisplayTextActivity extends BaseActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setFullScreenDialogClose(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setResult(Activity.RESULT_CANCELED);
- finish();
- }
- }, false);
+ setFullScreenDialogClose(Activity.RESULT_CANCELED, false);
// Handle intent actions
handleActions(savedInstanceState, getIntent());
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 b9f961d70..4e9c5a836 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -57,7 +57,7 @@ import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter;
import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAddedAdapter;
-import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
+import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.dialog.AddSubkeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.AddUserIdDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyDialogFragment;
@@ -68,7 +68,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
-public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel, OperationResult>
+public class EditKeyFragment extends QueueingCryptoOperationFragment<SaveKeyringParcel, OperationResult>
implements LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri";
@@ -192,7 +192,7 @@ public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel,
private void loadData(Uri dataUri) {
mDataUri = dataUri;
- Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
+ Log.i(Constants.TAG, "mDataUri: " + mDataUri);
// load the secret key ring. we do verify here that the passphrase is correct, so cached won't do
try {
@@ -618,13 +618,16 @@ public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel,
}
@Override
- public void onCryptoOperationSuccess(OperationResult result) {
+ public void onQueuedOperationSuccess(OperationResult result) {
+
+ // null-protected from Queueing*Fragment
+ Activity activity = getActivity();
// if good -> finish, return result to showkey and display there!
Intent intent = new Intent();
intent.putExtra(OperationResult.EXTRA_RESULT, result);
- getActivity().setResult(EditKeyActivity.RESULT_OK, intent);
- getActivity().finish();
+ activity.setResult(EditKeyActivity.RESULT_OK, intent);
+ activity.finish();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java
index d51b6e0ff..136787984 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -41,12 +42,7 @@ public class EncryptFilesActivity extends EncryptActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setFullScreenDialogClose(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- finish();
- }
- }, false);
+ setFullScreenDialogClose(Activity.RESULT_OK, false);
Intent intent = getIntent();
String action = intent.getAction();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
index b382e31d0..7b2796c69 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
@@ -387,13 +387,10 @@ public class EncryptFilesFragment
}
@Override
- public void onCryptoOperationSuccess(final SignEncryptResult result) {
+ public void onQueuedOperationSuccess(final SignEncryptResult result) {
+ // protected by Queueing*Fragment
FragmentActivity activity = getActivity();
- if (activity == null) {
- // it's gone, there's nothing we can do here
- return;
- }
if (mDeleteAfterEncrypt) {
// TODO make behavior coherent here
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
index cb26ea452..a849cdf12 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
@@ -39,12 +40,7 @@ public class EncryptTextActivity extends EncryptActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setFullScreenDialogClose(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- finish();
- }
- }, false);
+ setFullScreenDialogClose(Activity.RESULT_OK, false);
Intent intent = getIntent();
String action = intent.getAction();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
index 8d3738fbd..e307a85f8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
@@ -331,7 +331,7 @@ public class EncryptTextFragment
}
@Override
- public void onCryptoOperationSuccess(SignEncryptResult result) {
+ public void onQueuedOperationSuccess(SignEncryptResult result) {
if (mShareAfterEncrypt) {
// Share encrypted message/file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
index 2e8e6f6bd..076d6aed3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -95,6 +96,8 @@ public class ImportKeysActivity extends BaseNfcActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setFullScreenDialogClose(Activity.RESULT_CANCELED, true);
+
mProxyPrefs = Preferences.getPreferences(this).getProxyPrefs();
mImportButton = findViewById(R.id.import_import);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java
index f45f1b350..663ac3311 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java
@@ -257,7 +257,6 @@ public class ImportKeysProxyActivity extends FragmentActivity
Intent data = new Intent();
data.putExtras(returnData);
returnResult(data);
- return;
}
@Override
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 da3aae123..a50696cf3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -31,7 +31,6 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.os.Handler.Callback;
import android.os.Message;
import android.os.Messenger;
import android.provider.ContactsContract;
@@ -57,7 +56,6 @@ import com.getbase.floatingactionbutton.FloatingActionButton;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
-import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
@@ -67,10 +65,7 @@ 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.KeychainService;
-import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
@@ -102,6 +97,8 @@ public class ViewKeyActivity extends BaseNfcActivity implements
static final int REQUEST_QR_FINGERPRINT = 1;
static final int REQUEST_DELETE = 2;
static final int REQUEST_EXPORT = 3;
+ static final int REQUEST_CERTIFY = 4;
+
public static final String EXTRA_DISPLAY_RESULT = "display_result";
ProviderHelper mProviderHelper;
@@ -158,6 +155,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
super.onCreate(savedInstanceState);
mProviderHelper = new ProviderHelper(this);
+ mOperationHelper = new CryptoOperationHelper<>(this, this, null);
setTitle(null);
@@ -382,37 +380,14 @@ public class ViewKeyActivity extends BaseNfcActivity implements
Intent intent = new Intent(this, CertifyFingerprintActivity.class);
intent.setData(dataUri);
- startCertifyIntent(intent);
+ startActivityForResult(intent, REQUEST_CERTIFY);
}
private void certifyImmediate() {
Intent intent = new Intent(this, CertifyKeyActivity.class);
intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{mMasterKeyId});
- startCertifyIntent(intent);
- }
-
- private void startCertifyIntent(Intent intent) {
- // Message is received after signing is done in KeychainService
- ServiceProgressHandler saveHandler = new ServiceProgressHandler(this) {
- @Override
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
- super.handleMessage(message);
-
- if (message.arg1 == MessageStatus.OKAY.ordinal()) {
- Bundle data = message.getData();
- CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
-
- result.createNotify(ViewKeyActivity.this).show();
- }
- }
- };
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
-
- startActivityForResult(intent, 0);
+ startActivityForResult(intent, REQUEST_CERTIFY);
}
private void showQrCodeDialog() {
@@ -482,49 +457,58 @@ public class ViewKeyActivity extends BaseNfcActivity implements
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (mOperationHelper != null) {
- mOperationHelper.handleActivityResult(requestCode, resultCode, data);
+ if (mOperationHelper.handleActivityResult(requestCode, resultCode, data)) {
+ return;
+ }
+
+ if (resultCode != Activity.RESULT_OK) {
+ return;
}
- if (requestCode == REQUEST_QR_FINGERPRINT && resultCode == Activity.RESULT_OK) {
+ switch (requestCode) {
+ case REQUEST_QR_FINGERPRINT: {
+
+ // If there is an EXTRA_RESULT, that's an error. Just show it.
+ if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
+ OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
+ result.createNotify(this).show();
+ return;
+ }
- // If there is an EXTRA_RESULT, that's an error. Just show it.
- if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
- OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
- result.createNotify(this).show();
+ String fp = data.getStringExtra(ImportKeysProxyActivity.EXTRA_FINGERPRINT);
+ if (fp == null) {
+ Notify.create(this, R.string.error_scan_fp, Notify.LENGTH_LONG, Style.ERROR).show();
+ return;
+ }
+ if (mFingerprint.equalsIgnoreCase(fp)) {
+ certifyImmediate();
+ } else {
+ Notify.create(this, R.string.error_scan_match, Notify.LENGTH_LONG, Style.ERROR).show();
+ }
return;
}
- String fp = data.getStringExtra(ImportKeysProxyActivity.EXTRA_FINGERPRINT);
- if (fp == null) {
- Notify.create(this, "Error scanning fingerprint!",
- Notify.LENGTH_LONG, Notify.Style.ERROR).show();
+ case REQUEST_DELETE: {
+ deleteKey();
return;
}
- if (mFingerprint.equalsIgnoreCase(fp)) {
- certifyImmediate();
- } else {
- Notify.create(this, "Fingerprints did not match!",
- Notify.LENGTH_LONG, Notify.Style.ERROR).show();
- }
- return;
- }
+ case REQUEST_EXPORT: {
+ exportToFile(mDataUri, mProviderHelper);
+ return;
+ }
- if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK) {
- deleteKey();
+ case REQUEST_CERTIFY: {
+ if (data.hasExtra(OperationResult.EXTRA_RESULT)) {
+ OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
+ result.createNotify(this).show();
+ }
+ return;
+ }
}
- if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK) {
- exportToFile(mDataUri, mProviderHelper);
- }
+ super.onActivityResult(requestCode, resultCode, data);
- if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
- OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT);
- result.createNotify(this).show();
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- }
}
@Override
@@ -863,6 +847,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
mActionNfc.setVisibility(View.GONE);
}
mFab.setVisibility(View.VISIBLE);
+ // noinspection deprecation (no getDrawable with theme at current minApi level 15!)
mFab.setIconDrawable(getResources().getDrawable(R.drawable.ic_repeat_white_24dp));
} else {
mActionEncryptFile.setVisibility(View.VISIBLE);
@@ -952,7 +937,6 @@ public class ViewKeyActivity extends BaseNfcActivity implements
mKeyserver = cloudPrefs.keyserver;
}
- mOperationHelper = new CryptoOperationHelper<>(this, this, null);
mOperationHelper.cryptoOperation();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java
index 116d082d0..f980f297b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.ui;
+
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -39,12 +40,12 @@ import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.service.PromoteKeyringParcel;
-import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
+import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
public class ViewKeyYubiKeyFragment
- extends CryptoOperationFragment<PromoteKeyringParcel, PromoteKeyResult>
+ extends QueueingCryptoOperationFragment<PromoteKeyringParcel, PromoteKeyResult>
implements LoaderCallbacks<Cursor> {
public static final String ARG_MASTER_KEY_ID = "master_key_id";
@@ -76,7 +77,7 @@ public class ViewKeyYubiKeyFragment
}
public ViewKeyYubiKeyFragment() {
- super(R.string.progress_processing);
+ super(null);
}
@Override
@@ -214,7 +215,8 @@ public class ViewKeyYubiKeyFragment
}
@Override
- public void onCryptoOperationSuccess(PromoteKeyResult result) {
+ public void onQueuedOperationSuccess(PromoteKeyResult result) {
result.createNotify(getActivity()).show();
}
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java
index 847d76f30..9529d8689 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java
@@ -87,9 +87,7 @@ public abstract class BaseActivity extends AppCompatActivity {
mToolbar.setNavigationOnClickListener(cancelOnClickListener);
}
- /**
- * Close button only
- */
+ /** Close button only */
protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener, boolean white) {
if (white) {
setActionBarIcon(R.drawable.ic_close_white_24dp);
@@ -104,6 +102,17 @@ public abstract class BaseActivity extends AppCompatActivity {
setFullScreenDialogClose(cancelOnClickListener, true);
}
+ /** Close button only, with finish-action and given return status, white. */
+ protected void setFullScreenDialogClose(final int result, boolean white) {
+ setFullScreenDialogClose(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setResult(result);
+ finish();
+ }
+ }, white);
+ }
+
/**
* Inflate custom design with two buttons using drawables.
* This does not conform to the Material Design Guidelines, but we deviate here as this is used
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java
index 38b7075f2..9ce33f5a6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CachingCryptoOperationFragment.java
@@ -4,12 +4,11 @@ package org.sufficientlysecure.keychain.ui.base;
import android.os.Bundle;
import android.os.Parcelable;
-import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
public abstract class CachingCryptoOperationFragment <T extends Parcelable, S extends OperationResult>
- extends CryptoOperationFragment<T, S> {
+ extends QueueingCryptoOperationFragment<T, S> {
public static final String ARG_CACHED_ACTIONS = "cached_actions";
@@ -32,12 +31,14 @@ public abstract class CachingCryptoOperationFragment <T extends Parcelable, S ex
}
@Override
- public void onCryptoOperationSuccess(S result) {
+ public void onQueuedOperationSuccess(S result) {
+ super.onCryptoOperationSuccess(result);
mCachedActionsParcel = null;
}
@Override
- public void onCryptoOperationError(S result) {
+ public void onQueuedOperationError(S result) {
+ super.onCryptoOperationError(result);
mCachedActionsParcel = null;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
index bb0af5830..e77a05dc2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
@@ -46,7 +46,7 @@ import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
* @see KeychainService
*
*/
-public abstract class CryptoOperationFragment<T extends Parcelable, S extends OperationResult>
+abstract class CryptoOperationFragment<T extends Parcelable, S extends OperationResult>
extends Fragment implements CryptoOperationHelper.Callback<T, S> {
final private CryptoOperationHelper<T, S> mOperationHelper;
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 0db46a585..f72e87ca7 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
@@ -208,12 +208,9 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
return true;
}
}
-
- default: {
- return false;
- }
}
- return true;
+
+ return false;
}
protected void dismissProgress() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/QueueingCryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/QueueingCryptoOperationFragment.java
new file mode 100644
index 000000000..65b0ac0de
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/QueueingCryptoOperationFragment.java
@@ -0,0 +1,92 @@
+package org.sufficientlysecure.keychain.ui.base;
+
+
+import android.os.Bundle;
+import android.os.Parcelable;
+
+import org.sufficientlysecure.keychain.operations.results.OperationResult;
+
+
+/** CryptoOperationFragment which calls crypto operation results only while
+ * attached to Activity.
+ *
+ * This subclass of CryptoOperationFragment substitutes the onCryptoOperation*
+ * methods for onQueuedOperation* ones, which are ensured to be called while
+ * the fragment is attached to an Activity, possibly delaying the call until
+ * the Fragment is re-attached.
+ *
+ * TODO merge this functionality into CryptoOperationFragment?
+ *
+ * @see CryptoOperationFragment
+ */
+public abstract class QueueingCryptoOperationFragment<T extends Parcelable, S extends OperationResult>
+ extends CryptoOperationFragment<T,S> {
+
+ public static final String ARG_QUEUED_RESULT = "queued_result";
+ private S mQueuedResult;
+
+ public QueueingCryptoOperationFragment() {
+ super();
+ }
+
+ public QueueingCryptoOperationFragment(Integer initialProgressMsg) {
+ super(initialProgressMsg);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ if (mQueuedResult != null) {
+ try {
+ if (mQueuedResult.success()) {
+ onQueuedOperationSuccess(mQueuedResult);
+ } else {
+ onQueuedOperationError(mQueuedResult);
+ }
+ } finally {
+ mQueuedResult = null;
+ }
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ outState.putParcelable(ARG_QUEUED_RESULT, mQueuedResult);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (savedInstanceState != null) {
+ mQueuedResult = savedInstanceState.getParcelable(ARG_QUEUED_RESULT);
+ }
+ }
+
+ public abstract void onQueuedOperationSuccess(S result);
+
+ public void onQueuedOperationError(S result) {
+ super.onCryptoOperationError(result);
+ }
+
+ @Override
+ final public void onCryptoOperationSuccess(S result) {
+ if (getActivity() == null) {
+ mQueuedResult = result;
+ return;
+ }
+ onQueuedOperationSuccess(result);
+ }
+
+ @Override
+ final public void onCryptoOperationError(S result) {
+ if (getActivity() == null) {
+ mQueuedResult = result;
+ return;
+ }
+ onQueuedOperationError(result);
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
index 37e05a61d..f24df4f39 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditSubkeyExpiryDialogFragment.java
@@ -24,6 +24,7 @@ import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
+import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
@@ -36,6 +37,8 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.Log;
import java.util.Calendar;
@@ -72,16 +75,18 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
/**
* Creates dialog
*/
+ @NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Activity activity = getActivity();
+ Activity activity = getActivity();
+
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
long creation = getArguments().getLong(ARG_CREATION);
long expiry = getArguments().getLong(ARG_EXPIRY);
- Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ final Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
creationCal.setTime(new Date(creation * 1000));
- final Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ Calendar expiryCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
expiryCal.setTime(new Date(expiry * 1000));
// date picker works with default time zone, we need to convert from UTC to default timezone
@@ -175,10 +180,13 @@ public class EditSubkeyExpiryDialogFragment extends DialogFragment {
selectedCal.setTimeZone(TimeZone.getTimeZone("UTC"));
long numDays = (selectedCal.getTimeInMillis() / 86400000)
- - (expiryCal.getTimeInMillis() / 86400000);
+ - (creationCal.getTimeInMillis() / 86400000);
if (numDays <= 0) {
- Log.e(Constants.TAG, "Should not happen! Expiry num of days <= 0!");
- throw new RuntimeException();
+ Activity activity = getActivity();
+ if (activity != null) {
+ Notify.create(activity, R.string.error_expiry_past, Style.ERROR).show();
+ }
+ return;
}
expiry = selectedCal.getTime().getTime() / 1000;
}
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index adf30a747..a6052dffe 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -976,6 +976,7 @@
<!-- modifySecretKeyRing -->
<string name="msg_mr">"Modifying keyring %s"</string>
<string name="msg_mf_divert">"Will divert to smart card for crypto operations"</string>
+ <string name="msg_mf_error_divert_newsub">"Creation of new subkeys is not supported for 'divert-to-card' primary keys!"</string>
<string name="msg_mf_error_divert_serial">"The serial number of a 'divert-to-card' key must be 16 bytes! This is a programming error, please file a bug report!"</string>
<string name="msg_mf_error_encode">"Encoding exception!"</string>
<string name="msg_mf_error_fingerprint">"Actual key fingerprint does not match the expected one!"</string>
@@ -991,6 +992,7 @@
<string name="msg_mf_error_passphrase_master">"Fatal error decrypting master key! This is likely a programming error, please file a bug report!"</string>
<string name="msg_mf_error_pgp">"Internal OpenPGP error!"</string>
<string name="msg_mf_error_sig">"Signature exception!"</string>
+ <string name="msg_mf_error_sub_stripped">"Cannot modify stripped subkey %s!"</string>
<string name="msg_mf_error_subkey_missing">"Tried to operate on missing subkey %s!"</string>
<string name="msg_mf_error_conflicting_nfc_commands">"Cannot move key to smart card in same operation that creates an on-card signature."</string>
<string name="msg_mf_error_duplicate_keytocard_for_slot">"Smart card supports only one slot per key type."</string>
@@ -1432,5 +1434,8 @@
<string name="file_delete_exception">"Original file could not be deleted!"</string>
<string name="error_clipboard_empty">"Clipboard is empty!"</string>
<string name="error_clipboard_copy">"Error copying data to clipboard!"</string>
+ <string name="error_scan_fp">"Error scanning fingerprint!"</string>
+ <string name="error_scan_match">"Fingerprints did not match!"</string>
+ <string name="error_expiry_past">"Expiry date is in the past!"</string>
</resources>
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index f32730b47..c0e28cd4b 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -94,11 +94,11 @@ public class PgpKeyOperationTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+ Algorithm.DSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
+ Algorithm.RSA, 2048, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 2048, null, KeyFlags.ENCRYPT_COMMS, 0L));
+ Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
@@ -821,6 +821,15 @@ public class PgpKeyOperationTest {
Assert.assertEquals("new packet should have GNU_DUMMY protection mode stripped",
S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY, ((SecretKeyPacket) p).getS2K().getProtectionMode());
}
+
+ { // trying to edit a subkey with signing capability should fail
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, true));
+
+ assertModifyFailure("subkey modification for signing-enabled but stripped subkey should fail",
+ modified, parcel, LogType.MSG_MF_ERROR_SUB_STRIPPED);
+ }
+
}
@Test
@@ -829,7 +838,7 @@ public class PgpKeyOperationTest {
UncachedKeyRing modified;
{ // keytocard should fail with BAD_NFC_SIZE when presented with the RSA-1024 key
- long keyId = KeyringTestingHelper.getSubkeyId(ring, 0);
+ long keyId = KeyringTestingHelper.getSubkeyId(ring, 2);
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, false, true));
@@ -838,7 +847,7 @@ public class PgpKeyOperationTest {
}
{ // keytocard should fail with BAD_NFC_ALGO when presented with the DSA-1024 key
- long keyId = KeyringTestingHelper.getSubkeyId(ring, 1);
+ long keyId = KeyringTestingHelper.getSubkeyId(ring, 0);
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, false, true));
@@ -846,9 +855,10 @@ public class PgpKeyOperationTest {
parcel, cryptoInput, LogType.MSG_MF_ERROR_BAD_NFC_ALGO);
}
+ long keyId = KeyringTestingHelper.getSubkeyId(ring, 1);
+
{ // keytocard should return a pending NFC_MOVE_KEY_TO_CARD result when presented with the RSA-2048
// key, and then make key divert-to-card when it gets a serial in the cryptoInputParcel.
- long keyId = KeyringTestingHelper.getSubkeyId(ring, 2);
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, false, true));
@@ -880,7 +890,19 @@ public class PgpKeyOperationTest {
S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD, ((SecretKeyPacket) p).getS2K().getProtectionMode());
Assert.assertArrayEquals("new packet should have correct serial number as iv",
serial, ((SecretKeyPacket) p).getIV());
+ }
+
+ { // editing a signing subkey requires a primary key binding sig -> pendinginput
+ parcel.reset();
+ parcel.mChangeSubKeys.add(new SubkeyChange(keyId, true));
+ CanonicalizedSecretKeyRing secretRing =
+ new CanonicalizedSecretKeyRing(modified.getEncoded(), false, 0);
+ PgpKeyOperation op = new PgpKeyOperation(null);
+ PgpEditKeyResult result = op.modifySecretKeyRing(secretRing, cryptoInput, parcel);
+ Assert.assertTrue("keytocard operation should be pending", result.isPending());
+ Assert.assertEquals("required input should be RequiredInputType.NFC_SIGN",
+ RequiredInputType.NFC_SIGN, result.getRequiredInputParcel().mType);
}
}
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 0143ae289..ad4c1fb75 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
@@ -558,8 +558,9 @@ public class UncachedKeyringCanonicalizeTest {
PGPSignature cert = PgpKeyOperation.generateSubkeyBindingSignature(
PgpKeyOperation.getSignatureGenerator(masterSecretKey.getSecretKey(), cryptoInput),
cryptoInput.getSignatureTime(),
- masterPublicKey, masterSecretKey.getPrivateKey(), masterSecretKey.getPrivateKey(),
- masterPublicKey, masterSecretKey.getKeyUsage(), 0);
+ masterPublicKey, masterSecretKey.getPrivateKey(),
+ PgpKeyOperation.getSignatureGenerator(masterSecretKey.getSecretKey(), null),
+ masterSecretKey.getPrivateKey(), masterPublicKey, masterSecretKey.getKeyUsage(), 0);
PGPPublicKey subPubKey = PGPPublicKey.addSubkeyBindingCertification(masterPublicKey, cert);
PGPSecretKey sKey;