From 74c474e3e26c428153f15b7fab6b29738e882682 Mon Sep 17 00:00:00 2001 From: Max Mertens Date: Wed, 18 Mar 2015 17:49:57 +0100 Subject: Show HKP server results first in key cloud search. Fixes #1066 --- .../sufficientlysecure/keychain/keyimport/ImportKeysList.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java index 02cb502d0..ed096e9dc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java @@ -70,6 +70,7 @@ public class ImportKeysList extends ArrayList { modified = true; } + boolean incomingFromHkpServer = true; // we’re going to want to try to fetch the key from everywhere we found it, so remember // all the origins for (String origin : incoming.getOrigins()) { @@ -78,13 +79,19 @@ public class ImportKeysList extends ArrayList { // to work properly, Keybase-sourced entries need to pass along the extra if (KeybaseKeyserver.ORIGIN.equals(origin)) { existing.setExtraData(incoming.getExtraData()); + incomingFromHkpServer = false; } } + ArrayList incomingIDs = incoming.getUserIds(); ArrayList existingIDs = existing.getUserIds(); for (String incomingID : incomingIDs) { if (!existingIDs.contains(incomingID)) { - existingIDs.add(incomingID); + if (incomingFromHkpServer) { + existingIDs.add(0, incomingID); + } else { + existingIDs.add(incomingID); + } modified = true; } } -- cgit v1.2.3 From aab32b81b9b54e1a978006f33718a9525772ce53 Mon Sep 17 00:00:00 2001 From: Max Mertens Date: Wed, 18 Mar 2015 22:23:35 +0100 Subject: Added comments for server result sorting in key search --- .../org/sufficientlysecure/keychain/keyimport/ImportKeysList.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java index ed096e9dc..03439228b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java @@ -70,6 +70,7 @@ public class ImportKeysList extends ArrayList { modified = true; } + // keep track if this key result is from a HKP keyserver boolean incomingFromHkpServer = true; // we’re going to want to try to fetch the key from everywhere we found it, so remember // all the origins @@ -79,6 +80,7 @@ public class ImportKeysList extends ArrayList { // to work properly, Keybase-sourced entries need to pass along the extra if (KeybaseKeyserver.ORIGIN.equals(origin)) { existing.setExtraData(incoming.getExtraData()); + // one of the origins is not a HKP keyserver incomingFromHkpServer = false; } } @@ -87,6 +89,10 @@ public class ImportKeysList extends ArrayList { ArrayList existingIDs = existing.getUserIds(); for (String incomingID : incomingIDs) { if (!existingIDs.contains(incomingID)) { + // prepend HKP server results to the start of the list, + // so that the UI (for cloud key search, which is picking the first list item) + // shows the right main email address, as mail addresses returned by HKP servers + // are preferred over keybase.io IDs if (incomingFromHkpServer) { existingIDs.add(0, incomingID); } else { -- cgit v1.2.3 From 9c9f95c7acb92aad1f02e65271610fb3dca6c0dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 19 Mar 2015 03:03:46 +0100 Subject: New Passphrase class for safer passphrase handling in memory --- .../keychain/operations/BaseOperation.java | 5 +- .../keychain/operations/CertifyOperation.java | 3 +- .../keychain/operations/EditKeyOperation.java | 3 +- .../operations/results/DecryptVerifyResult.java | 11 +- .../operations/results/PgpSignEncryptResult.java | 8 +- .../keychain/pgp/CanonicalizedSecretKey.java | 5 +- .../keychain/pgp/PassphraseCacheInterface.java | 6 +- .../keychain/pgp/PgpDecryptVerify.java | 9 +- .../keychain/pgp/PgpKeyOperation.java | 25 ++-- .../keychain/pgp/PgpSignEncryptInput.java | 13 +- .../keychain/pgp/PgpSignEncryptOperation.java | 2 +- .../keychain/pgp/SignEncryptParcel.java | 10 +- .../keychain/remote/OpenPgpService.java | 7 +- .../keychain/service/KeychainIntentService.java | 7 +- .../keychain/service/PassphraseCacheService.java | 36 +++--- .../keychain/service/SaveKeyringParcel.java | 20 ++-- .../keychain/ui/CertifyKeyFragment.java | 4 +- .../keychain/ui/CreateKeyActivity.java | 11 +- .../keychain/ui/CreateKeyEmailFragment.java | 2 +- .../keychain/ui/CreateKeyFinalFragment.java | 9 +- .../keychain/ui/CreateKeyNameFragment.java | 15 +-- .../keychain/ui/CreateKeyPassphraseFragment.java | 13 +- .../keychain/ui/DecryptFilesFragment.java | 6 +- .../keychain/ui/DecryptFragment.java | 5 +- .../keychain/ui/DecryptTextFragment.java | 4 +- .../keychain/ui/EditKeyFragment.java | 11 +- .../keychain/ui/EncryptActivity.java | 7 +- .../keychain/ui/EncryptActivityInterface.java | 4 +- .../keychain/ui/EncryptFilesActivity.java | 9 +- .../keychain/ui/EncryptSymmetricFragment.java | 10 +- .../keychain/ui/EncryptTextActivity.java | 10 +- .../keychain/ui/PassphraseDialogActivity.java | 5 +- .../ui/dialog/SetPassphraseDialogFragment.java | 21 ++-- .../keychain/util/Passphrase.java | 131 +++++++++++++++++++++ 34 files changed, 307 insertions(+), 140 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java index 40dcbd78d..a824e73d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java @@ -24,6 +24,7 @@ import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.service.PassphraseCacheService; +import org.sufficientlysecure.keychain.util.Passphrase; import java.util.concurrent.atomic.AtomicBoolean; @@ -101,7 +102,7 @@ public abstract class BaseOperation implements PassphraseCacheInterface { } @Override - public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException { + public Passphrase getCachedPassphrase(long subKeyId) throws NoSecretKeyException { try { long masterKeyId = mProviderHelper.getMasterKeyId(subKeyId); return getCachedPassphrase(masterKeyId, subKeyId); @@ -111,7 +112,7 @@ public abstract class BaseOperation implements PassphraseCacheInterface { } @Override - public String getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException { + public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException { try { return PassphraseCacheService.getCachedPassphrase( mContext, masterKeyId, subKeyId); 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 ebf0dc70b..4ceb34722 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java @@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyActio import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; @@ -79,7 +80,7 @@ public class CertifyOperation extends BaseOperation { } // certification is always with the master key id, so use that one - String passphrase = getCachedPassphrase(parcel.mMasterKeyId, parcel.mMasterKeyId); + Passphrase passphrase = getCachedPassphrase(parcel.mMasterKeyId, parcel.mMasterKeyId); if (!certificationKey.unlock(passphrase)) { log.add(LogType.MSG_CRT_ERROR_UNLOCK, 2); 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 bcd842dd0..a179b53ee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -35,6 +35,7 @@ import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.ProgressScaler; import java.util.concurrent.atomic.AtomicBoolean; @@ -55,7 +56,7 @@ public class EditKeyOperation extends BaseOperation { super(context, providerHelper, progressable, cancelled); } - public EditKeyResult execute(SaveKeyringParcel saveParcel, String passphrase) { + public EditKeyResult execute(SaveKeyringParcel saveParcel, Passphrase passphrase) { OperationLog log = new OperationLog(); log.add(LogType.MSG_ED, 0); 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 86b37fea6..7df37cd9b 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 @@ -22,6 +22,7 @@ import android.os.Parcel; import org.openintents.openpgp.OpenPgpMetadata; import org.openintents.openpgp.OpenPgpSignatureResult; +import org.sufficientlysecure.keychain.util.Passphrase; public class DecryptVerifyResult extends OperationResult { @@ -37,7 +38,7 @@ public class DecryptVerifyResult extends OperationResult { long mNfcSubKeyId; byte[] mNfcSessionKey; - String mNfcPassphrase; + Passphrase mNfcPassphrase; OpenPgpSignatureResult mSignatureResult; OpenPgpMetadata mDecryptMetadata; @@ -53,7 +54,7 @@ public class DecryptVerifyResult extends OperationResult { mKeyIdPassphraseNeeded = keyIdPassphraseNeeded; } - public void setNfcState(long subKeyId, byte[] sessionKey, String passphrase) { + public void setNfcState(long subKeyId, byte[] sessionKey, Passphrase passphrase) { mNfcSubKeyId = subKeyId; mNfcSessionKey = sessionKey; mNfcPassphrase = passphrase; @@ -67,7 +68,7 @@ public class DecryptVerifyResult extends OperationResult { return mNfcSessionKey; } - public String getNfcPassphrase() { + public Passphrase getNfcPassphrase() { return mNfcPassphrase; } @@ -109,7 +110,7 @@ public class DecryptVerifyResult extends OperationResult { mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader()); mDecryptMetadata = source.readParcelable(OpenPgpMetadata.class.getClassLoader()); mNfcSessionKey = source.readInt() != 0 ? source.createByteArray() : null; - mNfcPassphrase = source.readString(); + mNfcPassphrase = source.readParcelable(Passphrase.class.getClassLoader()); } public int describeContents() { @@ -127,7 +128,7 @@ public class DecryptVerifyResult extends OperationResult { } else { dest.writeInt(0); } - dest.writeString(mNfcPassphrase); + dest.writeParcelable(mNfcPassphrase, flags); } public static final Creator CREATOR = new Creator() { 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 de2f64404..cf40001b3 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,8 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; +import org.sufficientlysecure.keychain.util.Passphrase; + import java.util.Date; public class PgpSignEncryptResult extends OperationResult { @@ -36,7 +38,7 @@ public class PgpSignEncryptResult extends OperationResult { byte[] mNfcHash; int mNfcAlgo; Date mNfcTimestamp; - String mNfcPassphrase; + Passphrase mNfcPassphrase; byte[] mDetachedSignature; public long getKeyIdPassphraseNeeded() { @@ -47,7 +49,7 @@ public class PgpSignEncryptResult extends OperationResult { mKeyIdPassphraseNeeded = keyIdPassphraseNeeded; } - public void setNfcData(long nfcKeyId, byte[] nfcHash, int nfcAlgo, Date nfcTimestamp, String passphrase) { + public void setNfcData(long nfcKeyId, byte[] nfcHash, int nfcAlgo, Date nfcTimestamp, Passphrase passphrase) { mNfcKeyId = nfcKeyId; mNfcHash = nfcHash; mNfcAlgo = nfcAlgo; @@ -75,7 +77,7 @@ public class PgpSignEncryptResult extends OperationResult { return mNfcTimestamp; } - public String getNfcPassphrase() { + public Passphrase getNfcPassphrase() { return mNfcPassphrase; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index ab91d7747..6ce77394c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -41,6 +41,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; import java.util.ArrayList; import java.util.Date; @@ -149,7 +150,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { /** * Returns true on right passphrase */ - public boolean unlock(String passphrase) throws PgpGeneralException { + public boolean unlock(Passphrase passphrase) throws PgpGeneralException { // handle keys on OpenPGP cards like they were unlocked if (mSecretKey.getS2K() != null && mSecretKey.getS2K().getType() == S2K.GNU_DUMMY_S2K @@ -161,7 +162,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { // try to extract keys using the passphrase try { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); + Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray()); mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor); mPrivateKeyState = PRIVATE_KEY_STATE_UNLOCKED; } catch (PGPException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PassphraseCacheInterface.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PassphraseCacheInterface.java index 0066bd23e..88ccccc6a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PassphraseCacheInterface.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PassphraseCacheInterface.java @@ -18,14 +18,16 @@ package org.sufficientlysecure.keychain.pgp; +import org.sufficientlysecure.keychain.util.Passphrase; + public interface PassphraseCacheInterface { public static class NoSecretKeyException extends Exception { public NoSecretKeyException() { } } - public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException; + public Passphrase getCachedPassphrase(long subKeyId) throws NoSecretKeyException; - public String getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException; + public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException; } 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 14bc56538..364a1067d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -60,6 +60,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.ProgressScaler; import java.io.BufferedInputStream; @@ -83,7 +84,7 @@ public class PgpDecryptVerify extends BaseOperation { private OutputStream mOutStream; private boolean mAllowSymmetricDecryption; - private String mPassphrase; + private Passphrase mPassphrase; private Set mAllowedKeyIds; private boolean mDecryptMetadataOnly; private byte[] mDecryptedSessionKey; @@ -118,7 +119,7 @@ public class PgpDecryptVerify extends BaseOperation { private OutputStream mOutStream = null; private Progressable mProgressable = null; private boolean mAllowSymmetricDecryption = true; - private String mPassphrase = null; + private Passphrase mPassphrase = null; private Set mAllowedKeyIds = null; private boolean mDecryptMetadataOnly = false; private byte[] mDecryptedSessionKey = null; @@ -159,7 +160,7 @@ public class PgpDecryptVerify extends BaseOperation { return this; } - public Builder setPassphrase(String passphrase) { + public Builder setPassphrase(Passphrase passphrase) { mPassphrase = passphrase; return this; } @@ -572,7 +573,7 @@ public class PgpDecryptVerify extends BaseOperation { .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(); PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder( digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - mPassphrase.toCharArray()); + mPassphrase.getCharArray()); clear = encryptedDataSymmetric.getDataStream(decryptorFactory); encryptedData = encryptedDataSymmetric; 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 8fb5392e3..b3bf92364 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -57,6 +57,7 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Primes; import org.sufficientlysecure.keychain.util.ProgressScaler; @@ -316,7 +317,7 @@ public class PgpKeyOperation { masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator()); subProgressPush(50, 100); - return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, "", log); + return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, new Passphrase(), log); } catch (PGPException e) { log.add(LogType.MSG_CR_ERROR_INTERNAL_PGP, indent); @@ -348,7 +349,7 @@ public class PgpKeyOperation { * */ public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel, - String passphrase) { + Passphrase passphrase) { OperationLog log = new OperationLog(); int indent = 0; @@ -404,7 +405,7 @@ public class PgpKeyOperation { private PgpEditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey, int masterKeyFlags, long masterKeyExpiry, - SaveKeyringParcel saveParcel, String passphrase, + SaveKeyringParcel saveParcel, Passphrase passphrase, OperationLog log) { int indent = 1; @@ -420,7 +421,7 @@ public class PgpKeyOperation { { try { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); + Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray()); masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor); } catch (PGPException e) { log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1); @@ -839,7 +840,7 @@ public class PgpKeyOperation { PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray()); PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder() .build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO); @@ -967,7 +968,7 @@ public class PgpKeyOperation { PGPSecretKeyRing sKR, PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, - String passphrase, + Passphrase passphrase, ChangeUnlockParcel newUnlock, OperationLog log, int indent) throws PGPException { @@ -1051,20 +1052,20 @@ public class PgpKeyOperation { private static PGPSecretKeyRing applyNewPassphrase( PGPSecretKeyRing sKR, PGPPublicKey masterPublicKey, - String passphrase, - String newPassphrase, + Passphrase passphrase, + Passphrase newPassphrase, OperationLog log, int indent) throws PGPException { PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build() .get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); + Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray()); // Build key encryptor based on new passphrase PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder( PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - newPassphrase.toCharArray()); + newPassphrase.getCharArray()); // noinspection unchecked for (PGPSecretKey sKey : new IterableIterator(sKR.getSecretKeys())) { @@ -1295,11 +1296,11 @@ public class PgpKeyOperation { private static PGPSignature generateSubkeyBindingSignature( PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, - PGPSecretKey sKey, PGPPublicKey pKey, int flags, long expiry, String passphrase) + PGPSecretKey sKey, PGPPublicKey pKey, int flags, long expiry, Passphrase passphrase) throws IOException, PGPException, SignatureException { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - passphrase.toCharArray()); + passphrase.getCharArray()); PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor); return generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, subPrivateKey, pKey, flags, expiry); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java index 2dec4b9c2..4a920685a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.Passphrase; import java.util.Date; @@ -29,12 +30,12 @@ public class PgpSignEncryptInput { protected boolean mEnableAsciiArmorOutput = false; protected int mCompressionId = CompressionAlgorithmTags.UNCOMPRESSED; protected long[] mEncryptionMasterKeyIds = null; - protected String mSymmetricPassphrase = null; + protected Passphrase mSymmetricPassphrase = null; protected int mSymmetricEncryptionAlgorithm = PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED; protected long mSignatureMasterKeyId = Constants.key.none; protected Long mSignatureSubKeyId = null; protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED; - protected String mSignaturePassphrase = null; + protected Passphrase mSignaturePassphrase = null; protected long mAdditionalEncryptId = Constants.key.none; protected byte[] mNfcSignedHash = null; protected Date mNfcCreationTimestamp = null; @@ -73,11 +74,11 @@ public class PgpSignEncryptInput { return this; } - public String getSignaturePassphrase() { + public Passphrase getSignaturePassphrase() { return mSignaturePassphrase; } - public PgpSignEncryptInput setSignaturePassphrase(String signaturePassphrase) { + public PgpSignEncryptInput setSignaturePassphrase(Passphrase signaturePassphrase) { mSignaturePassphrase = signaturePassphrase; return this; } @@ -118,11 +119,11 @@ public class PgpSignEncryptInput { return this; } - public String getSymmetricPassphrase() { + public Passphrase getSymmetricPassphrase() { return mSymmetricPassphrase; } - public PgpSignEncryptInput setSymmetricPassphrase(String symmetricPassphrase) { + public PgpSignEncryptInput setSymmetricPassphrase(Passphrase symmetricPassphrase) { mSymmetricPassphrase = symmetricPassphrase; return this; } 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 94e04060d..bd3c31d3a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -243,7 +243,7 @@ public class PgpSignEncryptOperation extends BaseOperation { log.add(LogType.MSG_PSE_SYMMETRIC, indent); JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator = - new JcePBEKeyEncryptionMethodGenerator(input.getSymmetricPassphrase().toCharArray()); + new JcePBEKeyEncryptionMethodGenerator(input.getSymmetricPassphrase().getCharArray()); cPk.addMethod(symmetricEncryptionGenerator); } else { log.add(LogType.MSG_PSE_ASYMMETRIC, indent); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java index 8e71e8815..975548c95 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java @@ -22,6 +22,8 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; +import org.sufficientlysecure.keychain.util.Passphrase; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -57,12 +59,12 @@ public class SignEncryptParcel extends PgpSignEncryptInput implements Parcelable mEnableAsciiArmorOutput = src.readInt() == 1; mCompressionId = src.readInt(); mEncryptionMasterKeyIds = src.createLongArray(); - mSymmetricPassphrase = src.readString(); + mSymmetricPassphrase = src.readParcelable(Passphrase.class.getClassLoader()); mSymmetricEncryptionAlgorithm = src.readInt(); mSignatureMasterKeyId = src.readLong(); mSignatureSubKeyId = src.readInt() == 1 ? src.readLong() : null; mSignatureHashAlgorithm = src.readInt(); - mSignaturePassphrase = src.readString(); + mSignaturePassphrase = src.readParcelable(Passphrase.class.getClassLoader()); mAdditionalEncryptId = src.readLong(); mNfcSignedHash = src.createByteArray(); mNfcCreationTimestamp = src.readInt() == 1 ? new Date(src.readLong()) : null; @@ -112,7 +114,7 @@ public class SignEncryptParcel extends PgpSignEncryptInput implements Parcelable dest.writeInt(mEnableAsciiArmorOutput ? 1 : 0); dest.writeInt(mCompressionId); dest.writeLongArray(mEncryptionMasterKeyIds); - dest.writeString(mSymmetricPassphrase); + dest.writeParcelable(mSymmetricPassphrase, flags); dest.writeInt(mSymmetricEncryptionAlgorithm); dest.writeLong(mSignatureMasterKeyId); if (mSignatureSubKeyId != null) { @@ -122,7 +124,7 @@ public class SignEncryptParcel extends PgpSignEncryptInput implements Parcelable dest.writeInt(0); } dest.writeInt(mSignatureHashAlgorithm); - dest.writeString(mSignaturePassphrase); + dest.writeParcelable(mSignaturePassphrase, flags); dest.writeLong(mAdditionalEncryptId); dest.writeByteArray(mNfcSignedHash); if (mNfcCreationTimestamp != null) { 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 a4bc95602..98a9ff44f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -54,6 +54,7 @@ import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; import org.sufficientlysecure.keychain.ui.ViewKeyActivity; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; import java.io.IOException; import java.io.InputStream; @@ -179,7 +180,7 @@ public class OpenPgpService extends RemoteService { return result; } - private PendingIntent getNfcSignPendingIntent(Intent data, long keyId, String pin, byte[] hashToSign, int hashAlgo) { + private PendingIntent getNfcSignPendingIntent(Intent data, long keyId, Passphrase pin, byte[] hashToSign, int hashAlgo) { // build PendingIntent for Yubikey NFC operations Intent intent = new Intent(getBaseContext(), NfcActivity.class); intent.setAction(NfcActivity.ACTION_SIGN_HASH); @@ -195,7 +196,7 @@ public class OpenPgpService extends RemoteService { PendingIntent.FLAG_CANCEL_CURRENT); } - private PendingIntent getNfcDecryptPendingIntent(Intent data, long subKeyId, String pin, byte[] encryptedSessionKey) { + private PendingIntent getNfcDecryptPendingIntent(Intent data, long subKeyId, Passphrase pin, byte[] encryptedSessionKey) { // build PendingIntent for Yubikey NFC operations Intent intent = new Intent(getBaseContext(), NfcActivity.class); intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY); @@ -508,7 +509,7 @@ public class OpenPgpService extends RemoteService { KeychainContract.ApiAllowedKeys.buildBaseUri(currentPkg)); } - String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); + Passphrase passphrase = data.getParcelableExtra(OpenPgpApi.EXTRA_PASSPHRASE); long inputLength = is.available(); InputData inputData = new InputData(is, inputLength); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index bf6a62782..d5f13f7ce 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -65,6 +65,7 @@ import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ParcelableFileCache; +import org.sufficientlysecure.keychain.util.Passphrase; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -281,7 +282,7 @@ public class KeychainIntentService extends IntentService implements Progressable try { /* Input */ - String passphrase = data.getString(DECRYPT_PASSPHRASE); + Passphrase passphrase = data.getParcelable(DECRYPT_PASSPHRASE); byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); InputData inputData = createDecryptInputData(data); @@ -411,7 +412,7 @@ public class KeychainIntentService extends IntentService implements Progressable try { /* Input */ - String passphrase = data.getString(DECRYPT_PASSPHRASE); + Passphrase passphrase = data.getParcelable(DECRYPT_PASSPHRASE); byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); InputData inputData = createDecryptInputData(data); @@ -469,7 +470,7 @@ public class KeychainIntentService extends IntentService implements Progressable // Input SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL); - String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE); + Passphrase passphrase = data.getParcelable(EDIT_KEYRING_PASSPHRASE); // Operation EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index 57881f8ee..ee481ad31 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Preferences; import java.util.Date; @@ -121,7 +122,7 @@ public class PassphraseCacheService extends Service { * new events to the alarm manager for new passphrases to let them timeout in the future. */ public static void addCachedPassphrase(Context context, long masterKeyId, long subKeyId, - String passphrase, + Passphrase passphrase, String primaryUserId) { Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + masterKeyId); @@ -143,7 +144,7 @@ public class PassphraseCacheService extends Service { * @return passphrase or null (if no passphrase is cached for this keyId) */ - public static String getCachedPassphrase(Context context, long masterKeyId, long subKeyId) throws KeyNotFoundException { + public static Passphrase getCachedPassphrase(Context context, long masterKeyId, long subKeyId) throws KeyNotFoundException { Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphrase() for masterKeyId " + masterKeyId + ", subKeyId " + subKeyId); @@ -190,7 +191,9 @@ public class PassphraseCacheService extends Service { switch (returnMessage.what) { case MSG_PASSPHRASE_CACHE_GET_OKAY: - return returnMessage.getData().getString(EXTRA_PASSPHRASE); + Bundle returnData = returnMessage.getData(); + returnData.setClassLoader(context.getClassLoader()); + return returnData.getParcelable(EXTRA_PASSPHRASE); case MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND: throw new KeyNotFoundException(); default: @@ -202,11 +205,11 @@ public class PassphraseCacheService extends Service { /** * Internal implementation to get cached passphrase. */ - private String getCachedPassphraseImpl(long masterKeyId, long subKeyId) throws ProviderHelper.NotFoundException { + private Passphrase getCachedPassphraseImpl(long masterKeyId, long subKeyId) throws ProviderHelper.NotFoundException { // passphrase for symmetric encryption? if (masterKeyId == Constants.key.symmetric) { Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption"); - String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric).getPassphrase(); + Passphrase cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric).getPassphrase(); if (cachedPassphrase == null) { return null; } @@ -232,13 +235,13 @@ public class PassphraseCacheService extends Service { case DIVERT_TO_CARD: if (Preferences.getPreferences(this).useDefaultYubikeyPin()) { Log.d(Constants.TAG, "PassphraseCacheService: Using default Yubikey PIN: 123456"); - return "123456"; // default Yubikey PIN, see http://www.yubico.com/2012/12/yubikey-neo-openpgp/ + return new Passphrase("123456"); // default Yubikey PIN, see http://www.yubico.com/2012/12/yubikey-neo-openpgp/ } else { Log.d(Constants.TAG, "PassphraseCacheService: NOT using default Yubikey PIN"); break; } case PASSPHRASE_EMPTY: - return ""; + return new Passphrase(""); case UNAVAILABLE: throw new ProviderHelper.NotFoundException("secret key for this subkey is not available"); case GNU_DUMMY: @@ -331,7 +334,7 @@ public class PassphraseCacheService extends Service { long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, -1); long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, -1); - String passphrase = intent.getStringExtra(EXTRA_PASSPHRASE); + Passphrase passphrase = intent.getParcelableExtra(EXTRA_PASSPHRASE); String primaryUserID = intent.getStringExtra(EXTRA_USER_ID); Log.d(Constants.TAG, @@ -373,10 +376,10 @@ public class PassphraseCacheService extends Service { Log.e(Constants.TAG, "PassphraseCacheService: Bad request, missing masterKeyId or subKeyId!"); msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND; } else { - String passphrase = getCachedPassphraseImpl(masterKeyId, subKeyId); + Passphrase passphrase = getCachedPassphraseImpl(masterKeyId, subKeyId); msg.what = MSG_PASSPHRASE_CACHE_GET_OKAY; Bundle bundle = new Bundle(); - bundle.putString(EXTRA_PASSPHRASE, passphrase); + bundle.putParcelable(EXTRA_PASSPHRASE, passphrase); msg.setData(bundle); } } catch (ProviderHelper.NotFoundException e) { @@ -412,7 +415,10 @@ public class PassphraseCacheService extends Service { * Called when one specific passphrase for keyId timed out */ private void timeout(Context context, long keyId) { - // remove passphrase corresponding to keyId from memory + CachedPassphrase cPass = mPassphraseCache.get(keyId); + // clean internal char[] from memory! + cPass.getPassphrase().removeFromMemory(); + // remove passphrase object mPassphraseCache.remove(keyId); Log.d(Constants.TAG, "PassphraseCacheService Timeout of keyId " + keyId + ", removed from memory!"); @@ -517,9 +523,9 @@ public class PassphraseCacheService extends Service { public class CachedPassphrase { private String primaryUserID; - private String passphrase; + private Passphrase passphrase; - public CachedPassphrase(String passphrase, String primaryUserID) { + public CachedPassphrase(Passphrase passphrase, String primaryUserID) { setPassphrase(passphrase); setPrimaryUserID(primaryUserID); } @@ -528,7 +534,7 @@ public class PassphraseCacheService extends Service { return primaryUserID; } - public String getPassphrase() { + public Passphrase getPassphrase() { return passphrase; } @@ -536,7 +542,7 @@ public class PassphraseCacheService extends Service { this.primaryUserID = primaryUserID; } - public void setPassphrase(String passphrase) { + public void setPassphrase(Passphrase passphrase) { this.passphrase = passphrase; } } 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 e2d0c03c9..9fd278c13 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -22,6 +22,7 @@ import android.os.Parcel; import android.os.Parcelable; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; +import org.sufficientlysecure.keychain.util.Passphrase; import java.io.Serializable; import java.util.ArrayList; @@ -296,33 +297,30 @@ public class SaveKeyringParcel implements Parcelable { public static class ChangeUnlockParcel implements Parcelable { // The new passphrase to use - public final String mNewPassphrase; + public final Passphrase mNewPassphrase; // A new pin to use. Must only contain [0-9]+ - public final String mNewPin; + public final Passphrase mNewPin; - public ChangeUnlockParcel(String newPassphrase) { + public ChangeUnlockParcel(Passphrase newPassphrase) { this(newPassphrase, null); } - public ChangeUnlockParcel(String newPassphrase, String newPin) { + public ChangeUnlockParcel(Passphrase newPassphrase, Passphrase newPin) { if (newPassphrase == null && newPin == null) { throw new RuntimeException("Cannot set both passphrase and pin. THIS IS A BUG!"); } - if (newPin != null && !newPin.matches("[0-9]+")) { - throw new RuntimeException("Pin must be numeric digits only. THIS IS A BUG!"); - } mNewPassphrase = newPassphrase; mNewPin = newPin; } public ChangeUnlockParcel(Parcel source) { - mNewPassphrase = source.readString(); - mNewPin = source.readString(); + mNewPassphrase = source.readParcelable(Passphrase.class.getClassLoader()); + mNewPin = source.readParcelable(Passphrase.class.getClassLoader()); } @Override public void writeToParcel(Parcel destination, int flags) { - destination.writeString(mNewPassphrase); - destination.writeString(mNewPin); + destination.writeParcelable(mNewPassphrase, flags); + destination.writeParcelable(mNewPin, flags); } @Override 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 9cb4e5f65..a0f89b06a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -62,6 +62,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner; import org.sufficientlysecure.keychain.ui.widget.KeySpinner; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Preferences; import java.lang.reflect.Method; @@ -318,7 +319,7 @@ public class CertifyKeyFragment extends LoaderFragment */ private void initiateCertifying() { // get the user's passphrase for this key (if required) - String passphrase; + Passphrase passphrase; try { passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), mSignMasterKeyId, mSignMasterKeyId); } catch (PassphraseCacheService.KeyNotFoundException e) { @@ -341,7 +342,6 @@ public class CertifyKeyFragment extends LoaderFragment switch (requestCode) { case REQUEST_CODE_PASSPHRASE: { if (resultCode == Activity.RESULT_OK && data != null) { - String passphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); startCertifying(); } return; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 2da5511b8..0eb9e948a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -23,11 +23,20 @@ import android.support.v4.app.FragmentTransaction; import org.sufficientlysecure.keychain.R; +import java.util.ArrayList; + public class CreateKeyActivity extends BaseActivity { public static final String EXTRA_NAME = "name"; public static final String EXTRA_EMAIL = "email"; + public class State { + String name; + String email; + ArrayList additionalEmails; + char[] passphrase; + } + public static enum FragAction { START, TO_RIGHT, @@ -44,7 +53,7 @@ public class CreateKeyActivity extends BaseActivity { getIntent().getStringExtra(EXTRA_NAME), getIntent().getStringExtra(EXTRA_EMAIL) ); - loadFragment(null, frag, FragAction.START); + loadFragment(savedInstanceState, frag, FragAction.START); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java index 66424e012..6a4dd7a41 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java @@ -85,7 +85,7 @@ public class CreateKeyEmailFragment extends Fragment { */ private static boolean isEditTextNotEmpty(Context context, EditText editText) { boolean output = true; - if (editText.getText().toString().length() == 0) { + if (editText.getText().length() == 0) { editText.setError(context.getString(R.string.create_key_empty)); editText.requestFocus(); output = false; 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 4871b5ae2..5f6bfdb11 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -45,6 +45,7 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Preferences; import java.util.ArrayList; @@ -72,7 +73,7 @@ public class CreateKeyFinalFragment extends Fragment { String mName; String mEmail; ArrayList mAdditionalEmails; - String mPassphrase; + Passphrase mPassphrase; SaveKeyringParcel mSaveKeyringParcel; @@ -81,14 +82,14 @@ public class CreateKeyFinalFragment extends Fragment { */ public static CreateKeyFinalFragment newInstance(String name, String email, ArrayList additionalEmails, - String passphrase) { + Passphrase passphrase) { CreateKeyFinalFragment frag = new CreateKeyFinalFragment(); Bundle args = new Bundle(); args.putString(ARG_NAME, name); args.putString(ARG_EMAIL, email); args.putStringArrayList(ARG_ADDITIONAL_EMAILS, additionalEmails); - args.putString(ARG_PASSPHRASE, passphrase); + args.putParcelable(ARG_PASSPHRASE, passphrase); frag.setArguments(args); @@ -111,7 +112,7 @@ public class CreateKeyFinalFragment extends Fragment { mName = getArguments().getString(ARG_NAME); mEmail = getArguments().getString(ARG_EMAIL); mAdditionalEmails = getArguments().getStringArrayList(ARG_ADDITIONAL_EMAILS); - mPassphrase = getArguments().getString(ARG_PASSPHRASE); + mPassphrase = getArguments().getParcelable(ARG_PASSPHRASE); // set values mNameEdit.setText(mName); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyNameFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyNameFragment.java index 50a3bd655..093d427b7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyNameFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyNameFragment.java @@ -68,7 +68,7 @@ public class CreateKeyNameFragment extends Fragment { */ private static boolean isEditTextNotEmpty(Context context, EditText editText) { boolean output = true; - if (editText.getText().toString().length() == 0) { + if (editText.getText().length() == 0) { editText.setError(context.getString(R.string.create_key_empty)); editText.requestFocus(); output = false; @@ -79,19 +79,6 @@ public class CreateKeyNameFragment extends Fragment { return output; } - private static boolean areEditTextsEqual(Context context, EditText editText1, EditText editText2) { - boolean output = true; - if (!editText1.getText().toString().equals(editText2.getText().toString())) { - editText2.setError(context.getString(R.string.create_key_passphrases_not_equal)); - editText2.requestFocus(); - output = false; - } else { - editText2.setError(null); - } - - return output; - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.create_key_name_fragment, container, false); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java index 055ea608b..a10c94093 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java @@ -34,6 +34,7 @@ import android.widget.EditText; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText; +import org.sufficientlysecure.keychain.util.Passphrase; import java.util.ArrayList; @@ -83,7 +84,7 @@ public class CreateKeyPassphraseFragment extends Fragment { */ private static boolean isEditTextNotEmpty(Context context, EditText editText) { boolean output = true; - if (editText.getText().toString().length() == 0) { + if (editText.getText().length() == 0) { editText.setError(context.getString(R.string.create_key_empty)); editText.requestFocus(); output = false; @@ -95,11 +96,13 @@ public class CreateKeyPassphraseFragment extends Fragment { } private static boolean areEditTextsEqual(Context context, EditText editText1, EditText editText2) { - boolean output = true; - if (!editText1.getText().toString().equals(editText2.getText().toString())) { + Passphrase p1 = new Passphrase(editText1); + Passphrase p2 = new Passphrase(editText2); + boolean output = (p1.equals(p2)); + + if (!output) { editText2.setError(context.getString(R.string.create_key_passphrases_not_equal)); editText2.requestFocus(); - output = false; } else { editText2.setError(null); } @@ -171,7 +174,7 @@ public class CreateKeyPassphraseFragment extends Fragment { mName, mEmail, mAdditionalEmails, - mPassphraseEdit.getText().toString() + new Passphrase(mPassphraseEdit.getText()) ); hideKeyboard(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java index 7e33843ea..71832daa5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java @@ -191,7 +191,7 @@ public class DecryptFilesFragment extends DecryptFragment { data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal()); data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri); - data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); + data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -265,7 +265,7 @@ public class DecryptFilesFragment extends DecryptFragment { data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal()); data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri); - data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); + data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -341,7 +341,7 @@ public class DecryptFilesFragment extends DecryptFragment { switch (requestCode) { case REQUEST_CODE_PASSPHRASE: { if (resultCode == Activity.RESULT_OK && data != null) { - mPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); + mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); decryptOriginalFilename(); } return; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index 513300cc5..63508e530 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; +import org.sufficientlysecure.keychain.util.Passphrase; public abstract class DecryptFragment extends Fragment { private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006; @@ -57,7 +58,7 @@ public abstract class DecryptFragment extends Fragment { // State - protected String mPassphrase; + protected Passphrase mPassphrase; protected byte[] mNfcDecryptedSessionKey; @Override @@ -100,7 +101,7 @@ public abstract class DecryptFragment extends Fragment { startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); } - protected void startNfcDecrypt(long subKeyId, String pin, byte[] encryptedSessionKey) { + protected void startNfcDecrypt(long subKeyId, Passphrase pin, byte[] encryptedSessionKey) { // build PendingIntent for Yubikey NFC operations Intent intent = new Intent(getActivity(), NfcActivity.class); intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index 1b34f6bf0..30cf739fc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -161,7 +161,7 @@ public class DecryptTextFragment extends DecryptFragment { // data data.putInt(KeychainIntentService.TARGET, IOType.BYTES.ordinal()); data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes()); - data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); + data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -247,7 +247,7 @@ public class DecryptTextFragment extends DecryptFragment { case REQUEST_CODE_PASSPHRASE: { if (resultCode == Activity.RESULT_OK && data != null) { - mPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); + mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); decryptStart(); } else { getActivity().finish(); 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 8d16fe47e..d2c1ab74c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -67,6 +67,7 @@ import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; public class EditKeyFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks { @@ -100,7 +101,7 @@ public class EditKeyFragment extends LoaderFragment implements private SaveKeyringParcel mSaveKeyringParcel; private String mPrimaryUserId; - private String mCurrentPassphrase; + private Passphrase mCurrentPassphrase; /** * Creates new instance of this fragment @@ -267,7 +268,7 @@ public class EditKeyFragment extends LoaderFragment implements switch (requestCode) { case REQUEST_CODE_PASSPHRASE: { if (resultCode == Activity.RESULT_OK && data != null) { - mCurrentPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); + mCurrentPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, EditKeyFragment.this); @@ -386,7 +387,7 @@ public class EditKeyFragment extends LoaderFragment implements // cache new returned passphrase! mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel( - data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE), + (Passphrase) data.getParcelable(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE), null ); } @@ -593,7 +594,7 @@ public class EditKeyFragment extends LoaderFragment implements getActivity().finish(); } - private void saveInDatabase(String passphrase) { + private void saveInDatabase(Passphrase passphrase) { Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel.toString()); KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( @@ -640,7 +641,7 @@ public class EditKeyFragment extends LoaderFragment implements // fill values for this action Bundle data = new Bundle(); - data.putString(KeychainIntentService.EDIT_KEYRING_PASSPHRASE, passphrase); + data.putParcelable(KeychainIntentService.EDIT_KEYRING_PASSPHRASE, passphrase); data.putParcelable(KeychainIntentService.EDIT_KEYRING_PARCEL, mSaveKeyringParcel); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 35dfcb87c..5438f667c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.util.Passphrase; import java.util.Date; @@ -41,7 +42,7 @@ public abstract class EncryptActivity extends BaseActivity { public static final int REQUEST_CODE_NFC = 0x00008002; // For NFC data - protected String mSigningKeyPassphrase = null; + protected Passphrase mSigningKeyPassphrase = null; protected Date mNfcTimestamp = null; protected byte[] mNfcHash = null; @@ -64,7 +65,7 @@ public abstract class EncryptActivity extends BaseActivity { startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); } - protected void startNfcSign(long keyId, String pin, byte[] hashToSign, int hashAlgo) { + protected void startNfcSign(long keyId, Passphrase pin, byte[] hashToSign, int hashAlgo) { // build PendingIntent for Yubikey NFC operations Intent intent = new Intent(this, NfcActivity.class); intent.setAction(NfcActivity.ACTION_SIGN_HASH); @@ -84,7 +85,7 @@ public abstract class EncryptActivity extends BaseActivity { switch (requestCode) { case REQUEST_CODE_PASSPHRASE: { if (resultCode == RESULT_OK && data != null) { - mSigningKeyPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); + mSigningKeyPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); startEncrypt(); return; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java index c89707c34..2a102c6c4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java @@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.ui; import android.net.Uri; +import org.sufficientlysecure.keychain.util.Passphrase; + import java.util.ArrayList; public interface EncryptActivityInterface { @@ -39,7 +41,7 @@ public interface EncryptActivityInterface { public void setEncryptionKeys(long[] encryptionKeys); public void setEncryptionUsers(String[] encryptionUsers); - public void setPassphrase(String passphrase); + public void setPassphrase(Passphrase passphrase); // ArrayList on purpose as only those are parcelable public ArrayList getInputUris(); 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 f1784fab3..0dd672c90 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.ShareHelper; import java.util.ArrayList; @@ -72,7 +73,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi private long mEncryptionKeyIds[] = null; private String mEncryptionUserIds[] = null; private long mSigningKeyId = Constants.key.none; - private String mPassphrase = ""; + private Passphrase mPassphrase = new Passphrase(); private ArrayList mInputUris; private ArrayList mOutputUris; @@ -136,7 +137,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi } @Override - public void setPassphrase(String passphrase) { + public void setPassphrase(Passphrase passphrase) { mPassphrase = passphrase; } @@ -243,8 +244,8 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi if (isModeSymmetric()) { Log.d(Constants.TAG, "Symmetric encryption enabled!"); - String passphrase = mPassphrase; - if (passphrase.length() == 0) { + Passphrase passphrase = mPassphrase; + if (passphrase.isEmpty()) { passphrase = null; } data.setSymmetricPassphrase(passphrase); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java index 86731b162..36b3c08f9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java @@ -28,6 +28,7 @@ import android.view.ViewGroup; import android.widget.EditText; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Passphrase; public class EncryptSymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener { @@ -67,8 +68,13 @@ public class EncryptSymmetricFragment extends Fragment implements EncryptActivit @Override public void afterTextChanged(Editable s) { // update passphrase in EncryptActivity - if (mPassphrase.getText().toString().equals(mPassphraseAgain.getText().toString())) { - mEncryptInterface.setPassphrase(s.toString()); + Passphrase p1 = new Passphrase(mPassphrase.getText()); + Passphrase p2 = new Passphrase(mPassphraseAgain.getText()); + boolean passesEquals = (p1.equals(p2)); + p1.removeFromMemory(); + p2.removeFromMemory(); + if (passesEquals) { + mEncryptInterface.setPassphrase(new Passphrase(mPassphrase.getText())); } else { mEncryptInterface.setPassphrase(null); } 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 14f2c492d..847f745d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.pgp.PgpConstants; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.ShareHelper; import java.util.ArrayList; @@ -70,7 +71,7 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv private String mEncryptionUserIds[] = null; // TODO Constants.key.none? What's wrong with a null value? private long mSigningKeyId = Constants.key.none; - private String mPassphrase = ""; + private Passphrase mPassphrase = new Passphrase(); private ArrayList mInputUris; private ArrayList mOutputUris; @@ -134,7 +135,8 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv } @Override - public void setPassphrase(String passphrase) { + public void setPassphrase(Passphrase passphrase) { + mPassphrase.removeFromMemory(); mPassphrase = passphrase; } @@ -223,8 +225,8 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv if (isModeSymmetric()) { Log.d(Constants.TAG, "Symmetric encryption enabled!"); - String passphrase = mPassphrase; - if (passphrase.length() == 0) { + Passphrase passphrase = mPassphrase; + if (passphrase.isEmpty()) { passphrase = null; } data.setSymmetricPassphrase(passphrase); 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 48509710a..360d30c82 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -55,6 +55,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Preferences; /** @@ -318,7 +319,7 @@ public class PassphraseDialogActivity extends FragmentActivity { positive.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - final String passphrase = mPassphraseEditText.getText().toString(); + final Passphrase passphrase = new Passphrase(mPassphraseEditText); // Early breakout if we are dealing with a symmetric key if (mSecretRing == null) { @@ -395,7 +396,7 @@ public class PassphraseDialogActivity extends FragmentActivity { }); } - private void finishCaching(String passphrase) { + private void finishCaching(Passphrase passphrase) { // any indication this isn't needed anymore, don't do it. if (mIsCancelled || getActivity() == null) { return; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java index b34dc2edc..947c316e0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java @@ -45,6 +45,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener { private static final String ARG_MESSENGER = "messenger"; @@ -67,12 +68,12 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi * @param messenger to communicate back after setting the passphrase * @return */ - public static SetPassphraseDialogFragment newInstance(Messenger messenger, String oldPassphrase, int title) { + public static SetPassphraseDialogFragment newInstance(Messenger messenger, Passphrase oldPassphrase, int title) { SetPassphraseDialogFragment frag = new SetPassphraseDialogFragment(); Bundle args = new Bundle(); args.putInt(ARG_TITLE, title); args.putParcelable(ARG_MESSENGER, messenger); - args.putString(ARG_OLD_PASSPHRASE, oldPassphrase); + args.putParcelable(ARG_OLD_PASSPHRASE, oldPassphrase); frag.setArguments(args); @@ -88,7 +89,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi int title = getArguments().getInt(ARG_TITLE); mMessenger = getArguments().getParcelable(ARG_MESSENGER); - String oldPassphrase = getArguments().getString(ARG_OLD_PASSPHRASE); + Passphrase oldPassphrase = getArguments().getParcelable(ARG_OLD_PASSPHRASE); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); @@ -103,7 +104,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi mNoPassphraseCheckBox = (CheckBox) view.findViewById(R.id.passphrase_no_passphrase); - if (TextUtils.isEmpty(oldPassphrase)) { + if (oldPassphrase.isEmpty()) { mNoPassphraseCheckBox.setChecked(true); mPassphraseEditText.setEnabled(false); mPassphraseAgainEditText.setEnabled(false); @@ -123,12 +124,12 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi public void onClick(DialogInterface dialog, int id) { dismiss(); - String passphrase1; + Passphrase passphrase1 = new Passphrase(); if (mNoPassphraseCheckBox.isChecked()) { - passphrase1 = ""; + passphrase1.setEmpty(); } else { - passphrase1 = mPassphraseEditText.getText().toString(); - String passphrase2 = mPassphraseAgainEditText.getText().toString(); + passphrase1 = new Passphrase(mPassphraseEditText); + Passphrase passphrase2 = new Passphrase(mPassphraseAgainEditText); if (!passphrase1.equals(passphrase2)) { Toast.makeText( activity, @@ -139,7 +140,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi return; } - if (passphrase1.equals("")) { + if (passphrase1.isEmpty()) { Toast.makeText( activity, getString(R.string.error_message, @@ -152,7 +153,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi // return resulting data back to activity Bundle data = new Bundle(); - data.putString(MESSAGE_NEW_PASSPHRASE, passphrase1); + data.putParcelable(MESSAGE_NEW_PASSPHRASE, passphrase1); sendMessageToHandler(MESSAGE_OKAY, data); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java new file mode 100644 index 000000000..34cb9af8e --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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.util; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.Editable; +import android.widget.EditText; + +import org.sufficientlysecure.keychain.Constants; + +import java.util.Arrays; + +public class Passphrase implements Parcelable { + private char[] mPassphrase; + + /** + * According to http://stackoverflow.com/a/15844273 EditText is not using String internally + * but char[]. Thus, we can get the char[] directly from it. + */ + public Passphrase(Editable editable) { + int pl = editable.length(); + mPassphrase = new char[pl]; + editable.getChars(0, pl, mPassphrase, 0); + // TODO: clean up internal char[] of EditText after getting the passphrase? +// editText.getText().replace() + System.gc(); + } + + public Passphrase(EditText editText) { + this(editText.getText()); + } + + public Passphrase(String passphrase) { + mPassphrase = passphrase.toCharArray(); + } + + public Passphrase() { + setEmpty(); + } + + public char[] getCharArray() { + return mPassphrase; + } + + public boolean isEmpty() { + return (mPassphrase.length == 0); + } + + public void setEmpty() { + removeFromMemory(); + mPassphrase = new char[0]; + } + + public void removeFromMemory() { + if (mPassphrase != null) { + Arrays.fill(mPassphrase, ' '); + System.gc(); + } + } + + @Override + public String toString() { + if (Constants.DEBUG) { + return "Passphrase{" + + "mPassphrase=" + Arrays.toString(mPassphrase) + + '}'; + } else { + return "Passphrase: hidden"; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Passphrase that = (Passphrase) o; + if (!Arrays.equals(mPassphrase, that.mPassphrase)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return mPassphrase != null ? Arrays.hashCode(mPassphrase) : 0; + } + + private Passphrase(Parcel source) { + mPassphrase = source.createCharArray(); + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeCharArray(mPassphrase); + } + + public static final Creator CREATOR = new Creator() { + public Passphrase createFromParcel(final Parcel source) { + return new Passphrase(source); + } + + public Passphrase[] newArray(final int size) { + return new Passphrase[size]; + } + }; + + public int describeContents() { + return 0; + } +} -- cgit v1.2.3 From e65efce333f700eb7f5303e5994e6a1b36f81462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 19 Mar 2015 03:30:12 +0100 Subject: Fix tests for Passphrase class --- .../main/java/org/sufficientlysecure/keychain/util/Passphrase.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java index 34cb9af8e..45dac3b64 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java @@ -46,6 +46,10 @@ public class Passphrase implements Parcelable { this(editText.getText()); } + public Passphrase(char[] passphrase) { + mPassphrase = passphrase; + } + public Passphrase(String passphrase) { mPassphrase = passphrase.toCharArray(); } -- cgit v1.2.3 From 0bcc2793c334ad04d3f7fd9f401eb6ab485f8c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 19 Mar 2015 13:58:26 +0100 Subject: Improve Passphrase class with finalize() --- .../keychain/util/Passphrase.java | 40 ++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java index 45dac3b64..06efdde4d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java @@ -26,6 +26,16 @@ import org.sufficientlysecure.keychain.Constants; import java.util.Arrays; +/** + * Passwords should not be stored as Strings in memory. + * This class wraps a char[] that can be erased after it is no longer used. + * See also: + *

+ * http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#PBEEx + * https://github.com/c-a-m/passfault/blob/master/core/src/main/java/org/owasp/passfault/SecureString.java + * http://stackoverflow.com/q/8881291 + * http://stackoverflow.com/a/15844273 + */ public class Passphrase implements Parcelable { private char[] mPassphrase; @@ -39,7 +49,6 @@ public class Passphrase implements Parcelable { editable.getChars(0, pl, mPassphrase, 0); // TODO: clean up internal char[] of EditText after getting the passphrase? // editText.getText().replace() - System.gc(); } public Passphrase(EditText editText) { @@ -54,6 +63,9 @@ public class Passphrase implements Parcelable { mPassphrase = passphrase.toCharArray(); } + /** + * Creates a passphrase object with an empty ("") passphrase + */ public Passphrase() { setEmpty(); } @@ -62,22 +74,38 @@ public class Passphrase implements Parcelable { return mPassphrase; } - public boolean isEmpty() { - return (mPassphrase.length == 0); - } - public void setEmpty() { removeFromMemory(); mPassphrase = new char[0]; } + public boolean isEmpty() { + return (length() == 0); + } + + public int length() { + return mPassphrase.length; + } + + public char charAt(int index) { + return mPassphrase[index]; + } + + /** + * Manually clear the underlying array holding the characters + */ public void removeFromMemory() { if (mPassphrase != null) { Arrays.fill(mPassphrase, ' '); - System.gc(); } } + @Override + public void finalize() throws Throwable { + removeFromMemory(); + super.finalize(); + } + @Override public String toString() { if (Constants.DEBUG) { -- cgit v1.2.3 From d122d27ebadbc883ba85e2256f1a0a29f791ee60 Mon Sep 17 00:00:00 2001 From: Manoj Khanna Date: Wed, 18 Mar 2015 17:53:24 +0530 Subject: Fixed a crash on ViewKeyActivity This occurs when deleting a key with a stripped master key from the ViewKeyActivity. --- .../keychain/ui/ViewKeyActivity.java | 91 ++++++++++++---------- .../keychain/util/ExportHelper.java | 15 ---- 2 files changed, 51 insertions(+), 55 deletions(-) (limited to 'OpenKeychain/src/main/java') 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 13a5ac269..5834fa502 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -74,6 +74,8 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus; +import org.sufficientlysecure.keychain.service.PassphraseCacheService; +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; @@ -310,31 +312,31 @@ public class ViewKeyActivity extends BaseActivity implements return true; } case R.id.menu_key_view_export_file: { - Intent mIntent = new Intent(this,PassphraseDialogActivity.class); - long keyId=0; try { - keyId = new ProviderHelper(this) - .getCachedPublicKeyRing(mDataUri) - .extractOrGetMasterKeyId(); - } catch (PgpKeyNotFoundException e) { - e.printStackTrace(); + if (PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId, mMasterKeyId) != null) { + exportToFile(mDataUri, mExportHelper, mProviderHelper); + return true; + } + + startPassphraseActivity(REQUEST_EXPORT); + } catch (PassphraseCacheService.KeyNotFoundException e) { + // This happens when the master key is stripped + exportToFile(mDataUri, mExportHelper, mProviderHelper); } - mIntent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID,keyId); - startActivityForResult(mIntent,REQUEST_EXPORT); return true; } case R.id.menu_key_view_delete: { - Intent mIntent = new Intent(this,PassphraseDialogActivity.class); - long keyId=0; try { - keyId = new ProviderHelper(this) - .getCachedPublicKeyRing(mDataUri) - .extractOrGetMasterKeyId(); - } catch (PgpKeyNotFoundException e) { - e.printStackTrace(); + if (PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId, mMasterKeyId) != null) { + deleteKey(); + return true; + } + + startPassphraseActivity(REQUEST_DELETE); + } catch (PassphraseCacheService.KeyNotFoundException e) { + // This happens when the master key is stripped + deleteKey(); } - mIntent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID,keyId); - startActivityForResult(mIntent,REQUEST_DELETE); return true; } case R.id.menu_key_view_advanced: { @@ -473,22 +475,32 @@ public class ViewKeyActivity extends BaseActivity implements ActivityCompat.startActivity(this, qrCodeIntent, opts); } - private void exportToFile(Uri dataUri, ExportHelper exportHelper, ProviderHelper providerHelper) - throws ProviderHelper.NotFoundException { - Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri); - - HashMap data = providerHelper.getGenericData( - baseUri, - new String[]{KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET}, - new int[]{ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER}); + private void startPassphraseActivity(int requestCode) { + Intent intent = new Intent(this, PassphraseDialogActivity.class); + intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, mMasterKeyId); + startActivityForResult(intent, requestCode); + } - exportHelper.showExportKeysDialog( - new long[]{(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)}, - Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) != 0) - ); + private void exportToFile(Uri dataUri, ExportHelper exportHelper, ProviderHelper providerHelper) { + try { + Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri); + + HashMap data = providerHelper.getGenericData( + baseUri, + new String[]{KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET}, + new int[]{ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER}); + + exportHelper.showExportKeysDialog( + new long[]{(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)}, + Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) != 0) + ); + } catch (ProviderHelper.NotFoundException e) { + Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR); + Log.e(Constants.TAG, "Key not found", e); + } } - private void deleteKey(Uri dataUri, ExportHelper exportHelper) { + private void deleteKey() { // Message is received after key is deleted Handler returnHandler = new Handler() { @Override @@ -500,7 +512,11 @@ public class ViewKeyActivity extends BaseActivity implements } }; - exportHelper.deleteKey(dataUri, returnHandler); + // 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"); } @Override @@ -531,18 +547,13 @@ public class ViewKeyActivity extends BaseActivity implements } if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK){ - deleteKey(mDataUri, mExportHelper); + deleteKey(); } + if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK){ - try { - exportToFile(mDataUri, mExportHelper, mProviderHelper); - } catch (ProviderHelper.NotFoundException e) { - Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR); - Log.e(Constants.TAG, "Key not found", e); - } + exportToFile(mDataUri, mExportHelper, mProviderHelper); } - if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); result.createNotify(this).show(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java index cda5892fe..7b164f2b2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java @@ -47,21 +47,6 @@ public class ExportHelper { this.mActivity = activity; } - public void deleteKey(Uri dataUri, Handler deleteHandler) { - try { - long masterKeyId = new ProviderHelper(mActivity).getCachedPublicKeyRing(dataUri) - .extractOrGetMasterKeyId(); - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(deleteHandler); - DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, - new long[]{ masterKeyId }); - deleteKeyDialog.show(mActivity.getSupportFragmentManager(), "deleteKeyDialog"); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - } - /** * Show dialog where to export keys */ -- cgit v1.2.3 From 6120365ee1e425acbc270b17c5cad621710777a9 Mon Sep 17 00:00:00 2001 From: Manoj Khanna Date: Thu, 19 Mar 2015 19:58:24 +0530 Subject: Fix for Issue #1114 Displays the snackbar above the keyboard on all activities. --- .../keychain/ui/util/Notify.java | 35 ++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java index 3bc29edb6..9736b5765 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java @@ -19,6 +19,11 @@ package org.sufficientlysecure.keychain.ui.util; import android.app.Activity; import android.content.res.Resources; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; +import android.view.View; +import android.view.ViewGroup; import com.nispok.snackbar.Snackbar; import com.nispok.snackbar.Snackbar.SnackbarDuration; @@ -61,11 +66,11 @@ public class Notify { break; } - SnackbarManager.show(bar); + showSnackbar(activity, bar); } - public static Showable createNotify (Activity activity, int resId, int duration, Style style) { + public static Showable createNotify (final Activity activity, int resId, int duration, Style style) { final Snackbar bar = getSnackbar(activity) .text(resId); @@ -90,7 +95,7 @@ public class Notify { return new Showable () { @Override public void show() { - SnackbarManager.show(bar); + showSnackbar(activity, bar); } }; } @@ -104,7 +109,7 @@ public class Notify { return createNotify(activity, msg, duration, style, null, 0); } - public static Showable createNotify(Activity activity, String msg, int duration, Style style, + public static Showable createNotify(final Activity activity, String msg, int duration, Style style, final ActionListener listener, int resIdAction) { final Snackbar bar = getSnackbar(activity) @@ -141,7 +146,7 @@ public class Notify { return new Showable () { @Override public void show() { - SnackbarManager.show(bar); + showSnackbar(activity, bar); } }; @@ -178,6 +183,26 @@ public class Notify { return bar; } + private static void showSnackbar(Activity activity, Snackbar snackbar) { + if (activity instanceof FragmentActivity) { + FragmentManager fragmentManager = ((FragmentActivity) activity).getSupportFragmentManager(); + + int count = fragmentManager.getBackStackEntryCount(); + Fragment fragment = fragmentManager.getFragments().get(count > 0 ? count - 1 : 0); + + if (fragment != null) { + View view = fragment.getView(); + + if (view != null) { + SnackbarManager.show(snackbar, (ViewGroup) view); + return; + } + } + } + + SnackbarManager.show(snackbar); + } + public interface Showable { public void show(); -- cgit v1.2.3 From 98817d13ee2e33b92f3a339df312709be027e964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 19 Mar 2015 17:16:23 +0100 Subject: Manage my keys wizard --- .../keychain/ui/CreateKeyActivity.java | 92 ++++++++---- .../keychain/ui/CreateKeyEmailFragment.java | 60 ++++---- .../keychain/ui/CreateKeyFinalFragment.java | 60 ++++---- .../keychain/ui/CreateKeyNameFragment.java | 40 +++--- .../keychain/ui/CreateKeyPassphraseFragment.java | 45 +++--- .../keychain/ui/CreateKeyStartFragment.java | 157 +++++++++++++++++++++ .../keychain/ui/FirstTimeActivity.java | 110 --------------- .../keychain/ui/KeyListFragment.java | 3 +- .../keychain/ui/MainActivity.java | 4 +- .../keychain/ui/widget/EmailEditText.java | 9 +- .../keychain/ui/widget/NameEditText.java | 6 +- 11 files changed, 323 insertions(+), 263 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 0eb9e948a..eb484302c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -22,6 +22,7 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Passphrase; import java.util.ArrayList; @@ -29,31 +30,62 @@ public class CreateKeyActivity extends BaseActivity { public static final String EXTRA_NAME = "name"; public static final String EXTRA_EMAIL = "email"; + public static final String EXTRA_FIRST_TIME = "first_time"; + public static final String EXTRA_ADDITIONAL_EMAILS = "additional_emails"; + public static final String EXTRA_PASSPHRASE = "passphrase"; - public class State { - String name; - String email; - ArrayList additionalEmails; - char[] passphrase; - } + public static final String FRAGMENT_TAG = "currentFragment"; - public static enum FragAction { - START, - TO_RIGHT, - TO_LEFT - } + String mName; + String mEmail; + ArrayList mAdditionalEmails; + Passphrase mPassphrase; + boolean mFirstTime; + + Fragment mCurrentFragment; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // pass extras into fragment - CreateKeyNameFragment frag = - CreateKeyNameFragment.newInstance( - getIntent().getStringExtra(EXTRA_NAME), - getIntent().getStringExtra(EXTRA_EMAIL) - ); - loadFragment(savedInstanceState, frag, FragAction.START); + // Check whether we're recreating a previously destroyed instance + if (savedInstanceState != null) { + // Restore value of members from saved state + mName = savedInstanceState.getString(EXTRA_NAME); + mEmail = savedInstanceState.getString(EXTRA_EMAIL); + mAdditionalEmails = savedInstanceState.getStringArrayList(EXTRA_ADDITIONAL_EMAILS); + mPassphrase = savedInstanceState.getParcelable(EXTRA_PASSPHRASE); + mFirstTime = savedInstanceState.getBoolean(EXTRA_FIRST_TIME); + + mCurrentFragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG); + } else { + // Initialize members with default values for a new instance + mName = getIntent().getStringExtra(EXTRA_NAME); + mEmail = getIntent().getStringExtra(EXTRA_EMAIL); + mFirstTime = getIntent().getBooleanExtra(EXTRA_FIRST_TIME, false); + + // Start with first fragment of wizard + CreateKeyStartFragment frag = CreateKeyStartFragment.newInstance(); + loadFragment(frag, FragAction.START); + } + + if (mFirstTime) { + setTitle(R.string.app_name); + setActionBarIcon(R.drawable.ic_launcher); + } else { + setTitle(R.string.title_manage_my_keys); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putString(EXTRA_NAME, mName); + outState.putString(EXTRA_EMAIL, mEmail); + outState.putStringArrayList(EXTRA_ADDITIONAL_EMAILS, mAdditionalEmails); + outState.putParcelable(EXTRA_PASSPHRASE, mPassphrase); + outState.putBoolean(EXTRA_FIRST_TIME, mFirstTime); } @Override @@ -61,23 +93,23 @@ public class CreateKeyActivity extends BaseActivity { setContentView(R.layout.create_key_activity); } - public void loadFragment(Bundle savedInstanceState, Fragment fragment, FragAction action) { - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; - } + public static enum FragAction { + START, + TO_RIGHT, + TO_LEFT + } + + public void loadFragment(Fragment fragment, FragAction action) { + mCurrentFragment = fragment; // Add the fragment to the 'fragment_container' FrameLayout - // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); switch (action) { case START: transaction.setCustomAnimations(0, 0); - transaction.replace(R.id.create_key_fragment_container, fragment) - .commitAllowingStateLoss(); + transaction.replace(R.id.create_key_fragment_container, fragment, FRAGMENT_TAG) + .commit(); break; case TO_LEFT: getSupportFragmentManager().popBackStackImmediate(); @@ -86,8 +118,8 @@ public class CreateKeyActivity extends BaseActivity { transaction.setCustomAnimations(R.anim.frag_slide_in_from_right, R.anim.frag_slide_out_to_left, R.anim.frag_slide_in_from_left, R.anim.frag_slide_out_to_right); transaction.addToBackStack(null); - transaction.replace(R.id.create_key_fragment_container, fragment) - .commitAllowingStateLoss(); + transaction.replace(R.id.create_key_fragment_container, fragment, FRAGMENT_TAG) + .commit(); break; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java index 6a4dd7a41..2e8a1f370 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java @@ -46,16 +46,12 @@ import java.util.List; public class CreateKeyEmailFragment extends Fragment { - public static final String ARG_NAME = "name"; - public static final String ARG_EMAIL = "email"; - CreateKeyActivity mCreateKeyActivity; EmailEditText mEmailEdit; RecyclerView mEmailsRecyclerView; View mBackButton; View mNextButton; - String mName; ArrayList mAdditionalEmailModels; EmailAdapter mEmailAdapter; @@ -63,13 +59,10 @@ public class CreateKeyEmailFragment extends Fragment { /** * Creates new instance of this fragment */ - public static CreateKeyEmailFragment newInstance(String name, String email) { + public static CreateKeyEmailFragment newInstance() { CreateKeyEmailFragment frag = new CreateKeyEmailFragment(); Bundle args = new Bundle(); - args.putString(ARG_NAME, name); - args.putString(ARG_EMAIL, email); - frag.setArguments(args); return frag; @@ -106,31 +99,33 @@ public class CreateKeyEmailFragment extends Fragment { mEmailsRecyclerView = (RecyclerView) view.findViewById(R.id.create_key_emails); // initial values - mName = getArguments().getString(ARG_NAME); - String email = getArguments().getString(ARG_EMAIL); - mEmailEdit.setText(email); + mEmailEdit.setText(mCreateKeyActivity.mEmail); // focus empty edit fields - if (email == null) { + if (mCreateKeyActivity.mEmail == null) { mEmailEdit.requestFocus(); } mBackButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - mCreateKeyActivity.loadFragment(null, null, FragAction.TO_LEFT); + mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT); } }); mNextButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - createKeyCheck(); + nextClicked(); } }); mEmailsRecyclerView.setHasFixedSize(true); mEmailsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); mEmailsRecyclerView.setItemAnimator(new DefaultItemAnimator()); + // initial values mAdditionalEmailModels = new ArrayList<>(); + if (mCreateKeyActivity.mAdditionalEmails != null) { + setAdditionalEmails(mCreateKeyActivity.mAdditionalEmails); + } mEmailAdapter = new EmailAdapter(mAdditionalEmailModels, new View.OnClickListener() { @Override public void onClick(View v) { @@ -171,25 +166,38 @@ public class CreateKeyEmailFragment extends Fragment { mCreateKeyActivity = (CreateKeyActivity) getActivity(); } - private void createKeyCheck() { + private void nextClicked() { if (isEditTextNotEmpty(getActivity(), mEmailEdit)) { + // save state + mCreateKeyActivity.mEmail = mEmailEdit.getText().toString(); + mCreateKeyActivity.mAdditionalEmails = getAdditionalEmails(); - ArrayList emails = new ArrayList<>(); - for (EmailAdapter.ViewModel holder : mAdditionalEmailModels) { - emails.add(holder.toString()); - } + CreateKeyPassphraseFragment frag = CreateKeyPassphraseFragment.newInstance(); + mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT); + } + } - CreateKeyPassphraseFragment frag = - CreateKeyPassphraseFragment.newInstance( - mName, - mEmailEdit.getText().toString(), - emails - ); + private ArrayList getAdditionalEmails() { + ArrayList emails = new ArrayList<>(); + for (EmailAdapter.ViewModel holder : mAdditionalEmailModels) { + emails.add(holder.toString()); + } + return emails; + } - mCreateKeyActivity.loadFragment(null, frag, FragAction.TO_RIGHT); + private void setAdditionalEmails(ArrayList emails) { + for (String email : emails) { + mAdditionalEmailModels.add(new EmailAdapter.ViewModel(email)); } } + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + // save state in activity + mCreateKeyActivity.mAdditionalEmails = getAdditionalEmails(); + } + public static class EmailAdapter extends RecyclerView.Adapter { private List mDataset; private View.OnClickListener mFooterOnClickListener; 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 5f6bfdb11..75f49a426 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -65,32 +65,15 @@ public class CreateKeyFinalFragment extends Fragment { TextView mEditText; View mEditButton; - public static final String ARG_NAME = "name"; - public static final String ARG_EMAIL = "email"; - public static final String ARG_ADDITIONAL_EMAILS = "emails"; - public static final String ARG_PASSPHRASE = "passphrase"; - - String mName; - String mEmail; - ArrayList mAdditionalEmails; - Passphrase mPassphrase; - SaveKeyringParcel mSaveKeyringParcel; /** * Creates new instance of this fragment */ - public static CreateKeyFinalFragment newInstance(String name, String email, - ArrayList additionalEmails, - Passphrase passphrase) { + public static CreateKeyFinalFragment newInstance() { CreateKeyFinalFragment frag = new CreateKeyFinalFragment(); Bundle args = new Bundle(); - args.putString(ARG_NAME, name); - args.putString(ARG_EMAIL, email); - args.putStringArrayList(ARG_ADDITIONAL_EMAILS, additionalEmails); - args.putParcelable(ARG_PASSPHRASE, passphrase); - frag.setArguments(args); return frag; @@ -108,17 +91,11 @@ public class CreateKeyFinalFragment extends Fragment { mEditText = (TextView) view.findViewById(R.id.create_key_edit_text); mEditButton = view.findViewById(R.id.create_key_edit_button); - // get args - mName = getArguments().getString(ARG_NAME); - mEmail = getArguments().getString(ARG_EMAIL); - mAdditionalEmails = getArguments().getStringArrayList(ARG_ADDITIONAL_EMAILS); - mPassphrase = getArguments().getParcelable(ARG_PASSPHRASE); - // set values - mNameEdit.setText(mName); - if (mAdditionalEmails != null && mAdditionalEmails.size() > 0) { - String emailText = mEmail + ", "; - Iterator it = mAdditionalEmails.iterator(); + mNameEdit.setText(mCreateKeyActivity.mName); + if (mCreateKeyActivity.mAdditionalEmails != null && mCreateKeyActivity.mAdditionalEmails.size() > 0) { + String emailText = mCreateKeyActivity.mEmail + ", "; + Iterator it = mCreateKeyActivity.mAdditionalEmails.iterator(); while (it.hasNext()) { Object next = it.next(); emailText += next; @@ -128,7 +105,7 @@ public class CreateKeyFinalFragment extends Fragment { } mEmailEdit.setText(emailText); } else { - mEmailEdit.setText(mEmail); + mEmailEdit.setText(mCreateKeyActivity.mEmail); } mCreateButton.setOnClickListener(new View.OnClickListener() { @@ -141,7 +118,7 @@ public class CreateKeyFinalFragment extends Fragment { mBackButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - mCreateKeyActivity.loadFragment(null, null, FragAction.TO_LEFT); + mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT); } }); @@ -157,6 +134,12 @@ public class CreateKeyFinalFragment extends Fragment { return view; } + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mCreateKeyActivity = (CreateKeyActivity) getActivity(); + } + @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { @@ -187,17 +170,22 @@ public class CreateKeyFinalFragment extends Fragment { Algorithm.RSA, 4096, null, KeyFlags.SIGN_DATA, 0L)); mSaveKeyringParcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd( Algorithm.RSA, 4096, null, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, 0L)); - String userId = KeyRing.createUserId(new KeyRing.UserId(mName, mEmail, null)); + String userId = KeyRing.createUserId( + new KeyRing.UserId(mCreateKeyActivity.mName, mCreateKeyActivity.mEmail, null) + ); mSaveKeyringParcel.mAddUserIds.add(userId); mSaveKeyringParcel.mChangePrimaryUserId = userId; - if (mAdditionalEmails != null && mAdditionalEmails.size() > 0) { - for (String email : mAdditionalEmails) { - String thisUserId = KeyRing.createUserId(new KeyRing.UserId(mName, email, null)); + if (mCreateKeyActivity.mAdditionalEmails != null + && mCreateKeyActivity.mAdditionalEmails.size() > 0) { + for (String email : mCreateKeyActivity.mAdditionalEmails) { + String thisUserId = KeyRing.createUserId( + new KeyRing.UserId(mCreateKeyActivity.mName, email, null) + ); mSaveKeyringParcel.mAddUserIds.add(thisUserId); } } - mSaveKeyringParcel.mNewUnlock = mPassphrase != null - ? new ChangeUnlockParcel(mPassphrase, null) + mSaveKeyringParcel.mNewUnlock = mCreateKeyActivity.mPassphrase != null + ? new ChangeUnlockParcel(mCreateKeyActivity.mPassphrase, null) : null; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyNameFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyNameFragment.java index 093d427b7..7480367bb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyNameFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyNameFragment.java @@ -24,34 +24,26 @@ import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; -import org.sufficientlysecure.keychain.ui.widget.EmailEditText; import org.sufficientlysecure.keychain.ui.widget.NameEditText; public class CreateKeyNameFragment extends Fragment { - public static final String ARG_NAME = "name"; - public static final String ARG_EMAIL = "email"; - CreateKeyActivity mCreateKeyActivity; NameEditText mNameEdit; + View mBackButton; View mNextButton; - String mEmail; - /** * Creates new instance of this fragment */ - public static CreateKeyNameFragment newInstance(String name, String email) { + public static CreateKeyNameFragment newInstance() { CreateKeyNameFragment frag = new CreateKeyNameFragment(); Bundle args = new Bundle(); - args.putString(ARG_NAME, name); - args.putString(ARG_EMAIL, email); frag.setArguments(args); @@ -84,21 +76,26 @@ public class CreateKeyNameFragment extends Fragment { View view = inflater.inflate(R.layout.create_key_name_fragment, container, false); mNameEdit = (NameEditText) view.findViewById(R.id.create_key_name); + mBackButton = view.findViewById(R.id.create_key_back_button); mNextButton = view.findViewById(R.id.create_key_next_button); // initial values - String name = getArguments().getString(ARG_NAME); - mEmail = getArguments().getString(ARG_EMAIL); - mNameEdit.setText(name); + mNameEdit.setText(mCreateKeyActivity.mName); // focus empty edit fields - if (name == null) { + if (mCreateKeyActivity.mName == null) { mNameEdit.requestFocus(); } + mBackButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT); + } + }); mNextButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - createKeyCheck(); + nextClicked(); } }); @@ -111,16 +108,13 @@ public class CreateKeyNameFragment extends Fragment { mCreateKeyActivity = (CreateKeyActivity) getActivity(); } - private void createKeyCheck() { + private void nextClicked() { if (isEditTextNotEmpty(getActivity(), mNameEdit)) { + // save state + mCreateKeyActivity.mName = mNameEdit.getText().toString(); - CreateKeyEmailFragment frag = - CreateKeyEmailFragment.newInstance( - mNameEdit.getText().toString(), - mEmail - ); - - mCreateKeyActivity.loadFragment(null, frag, FragAction.TO_RIGHT); + CreateKeyEmailFragment frag = CreateKeyEmailFragment.newInstance(); + mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java index a10c94093..32173edf7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyPassphraseFragment.java @@ -21,6 +21,7 @@ import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; +import android.text.Editable; import android.text.method.HideReturnsTransformationMethod; import android.text.method.PasswordTransformationMethod; import android.view.LayoutInflater; @@ -37,18 +38,10 @@ import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText; import org.sufficientlysecure.keychain.util.Passphrase; import java.util.ArrayList; +import java.util.Arrays; public class CreateKeyPassphraseFragment extends Fragment { - public static final String ARG_NAME = "name"; - public static final String ARG_EMAIL = "email"; - public static final String ARG_ADDITIONAL_EMAILS = "emails"; - - // model - String mName; - String mEmail; - ArrayList mAdditionalEmails; - // view CreateKeyActivity mCreateKeyActivity; PassphraseEditText mPassphraseEdit; @@ -60,15 +53,10 @@ public class CreateKeyPassphraseFragment extends Fragment { /** * Creates new instance of this fragment */ - public static CreateKeyPassphraseFragment newInstance(String name, String email, - ArrayList additionalEmails) { + public static CreateKeyPassphraseFragment newInstance() { CreateKeyPassphraseFragment frag = new CreateKeyPassphraseFragment(); Bundle args = new Bundle(); - args.putString(ARG_NAME, name); - args.putString(ARG_EMAIL, email); - args.putStringArrayList(ARG_ADDITIONAL_EMAILS, additionalEmails); - frag.setArguments(args); return frag; @@ -121,9 +109,12 @@ public class CreateKeyPassphraseFragment extends Fragment { mNextButton = view.findViewById(R.id.create_key_next_button); // initial values - mName = getArguments().getString(ARG_NAME); - mEmail = getArguments().getString(ARG_EMAIL); - mAdditionalEmails = getArguments().getStringArrayList(ARG_ADDITIONAL_EMAILS); + // TODO: using String here is unsafe... + if (mCreateKeyActivity.mPassphrase != null) { + mPassphraseEdit.setText(Arrays.toString(mCreateKeyActivity.mPassphrase.getCharArray())); + mPassphraseEditAgain.setText(Arrays.toString(mCreateKeyActivity.mPassphrase.getCharArray())); + } + mPassphraseEdit.requestFocus(); mBackButton.setOnClickListener(new View.OnClickListener() { @Override @@ -134,7 +125,7 @@ public class CreateKeyPassphraseFragment extends Fragment { mNextButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - createKeyCheck(); + nextClicked(); } }); mShowPassphrase.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @@ -162,23 +153,19 @@ public class CreateKeyPassphraseFragment extends Fragment { private void back() { hideKeyboard(); - mCreateKeyActivity.loadFragment(null, null, FragAction.TO_LEFT); + mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT); } - private void createKeyCheck() { + private void nextClicked() { if (isEditTextNotEmpty(getActivity(), mPassphraseEdit) && areEditTextsEqual(getActivity(), mPassphraseEdit, mPassphraseEditAgain)) { - CreateKeyFinalFragment frag = - CreateKeyFinalFragment.newInstance( - mName, - mEmail, - mAdditionalEmails, - new Passphrase(mPassphraseEdit.getText()) - ); + // save state + mCreateKeyActivity.mPassphrase = new Passphrase(mPassphraseEdit); + CreateKeyFinalFragment frag = CreateKeyFinalFragment.newInstance(); hideKeyboard(); - mCreateKeyActivity.loadFragment(null, frag, FragAction.TO_RIGHT); + mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java new file mode 100644 index 000000000..180a52a1c --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * 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.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; +import android.support.v4.app.Fragment; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; +import org.sufficientlysecure.keychain.ui.dialog.AddEmailDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; +import org.sufficientlysecure.keychain.ui.widget.EmailEditText; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; + +import java.util.ArrayList; +import java.util.List; + +public class CreateKeyStartFragment extends Fragment { + + CreateKeyActivity mCreateKeyActivity; + + View mCreateKey; + View mImportKey; + View mYubiKey; + TextView mCancel; + public static final int REQUEST_CODE_CREATE_OR_IMPORT_KEY = 0x00007012; + + /** + * Creates new instance of this fragment + */ + public static CreateKeyStartFragment newInstance() { + CreateKeyStartFragment frag = new CreateKeyStartFragment(); + + Bundle args = new Bundle(); + + frag.setArguments(args); + + return frag; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.create_key_start_fragment, container, false); + + mCreateKey = view.findViewById(R.id.create_key_create_key_button); + mImportKey = view.findViewById(R.id.create_key_import_button); +// mYubiKey = view.findViewById(R.id.create_key_yubikey_button); + mCancel = (TextView) view.findViewById(R.id.create_key_cancel); + + if (mCreateKeyActivity.mFirstTime) { + mCancel.setText(R.string.first_time_skip); + } else { + mCancel.setText(R.string.btn_do_not_save); + } + + mCreateKey.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CreateKeyNameFragment frag = CreateKeyNameFragment.newInstance(); + mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT); + } + }); + + mImportKey.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(mCreateKeyActivity, ImportKeysActivity.class); + intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN); + startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY); + } + }); + + mCancel.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finishSetup(null); + } + }); + + return view; + } + + + private void finishSetup(Intent srcData) { + if (mCreateKeyActivity.mFirstTime) { + Preferences prefs = Preferences.getPreferences(mCreateKeyActivity); + prefs.setFirstTime(false); + } + Intent intent = new Intent(mCreateKeyActivity, MainActivity.class); + // give intent through to display notify + if (srcData != null) { + intent.putExtras(srcData); + } + startActivity(intent); + mCreateKeyActivity.finish(); + } + + // workaround for https://code.google.com/p/android/issues/detail?id=61394 +// @Override +// public boolean onKeyDown(int keyCode, KeyEvent event) { +// return keyCode == KeyEvent.KEYCODE_MENU || super.onKeyDown(keyCode, event); +// } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == REQUEST_CODE_CREATE_OR_IMPORT_KEY) { + if (resultCode == Activity.RESULT_OK) { + finishSetup(data); + } + } else { + Log.e(Constants.TAG, "No valid request code!"); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mCreateKeyActivity = (CreateKeyActivity) getActivity(); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java deleted file mode 100644 index 393e15cfa..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * 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.content.Intent; -import android.os.Bundle; -import android.view.KeyEvent; -import android.view.View; -import android.view.Window; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Preferences; - -public class FirstTimeActivity extends BaseActivity { - - View mCreateKey; - View mImportKey; - View mSkipSetup; - - public static final int REQUEST_CODE_CREATE_OR_IMPORT_KEY = 0x00007012; - - @Override - protected void onCreate(Bundle savedInstanceState) { - supportRequestWindowFeature(Window.FEATURE_NO_TITLE); - - super.onCreate(savedInstanceState); - - mCreateKey = findViewById(R.id.first_time_create_key); - mImportKey = findViewById(R.id.first_time_import_key); - mSkipSetup = findViewById(R.id.first_time_cancel); - - mSkipSetup.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finishSetup(null); - } - }); - - mImportKey.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(FirstTimeActivity.this, ImportKeysActivity.class); - intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN); - startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY); - } - }); - - mCreateKey.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(FirstTimeActivity.this, CreateKeyActivity.class); - startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY); - } - }); - } - - @Override - protected void initLayout() { - setContentView(R.layout.first_time_activity); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if (requestCode == REQUEST_CODE_CREATE_OR_IMPORT_KEY) { - if (resultCode == RESULT_OK) { - finishSetup(data); - } - } else { - Log.e(Constants.TAG, "No valid request code!"); - } - } - - private void finishSetup(Intent srcData) { - Preferences prefs = Preferences.getPreferences(this); - prefs.setFirstTime(false); - Intent intent = new Intent(this, MainActivity.class); - // give intent through to display notify - if (srcData != null) { - intent.putExtras(srcData); - } - startActivity(intent); - finish(); - } - - // workaround for https://code.google.com/p/android/issues/detail?id=61394 - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - return keyCode == KeyEvent.KEYCODE_MENU || super.onKeyDown(keyCode, event); - } - -} 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 4b604add8..f8939f3d1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -489,7 +489,8 @@ public class KeyListFragment extends LoaderFragment case R.id.menu_key_list_debug_first_time: Preferences prefs = Preferences.getPreferences(getActivity()); prefs.setFirstTime(true); - Intent intent = new Intent(getActivity(), FirstTimeActivity.class); + Intent intent = new Intent(getActivity(), CreateKeyActivity.class); + intent.putExtra(CreateKeyActivity.EXTRA_FIRST_TIME, true); startActivity(intent); getActivity().finish(); return true; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index b6b2fcb8a..5fa3edba4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -54,7 +54,9 @@ public class MainActivity extends MaterialNavigationDrawer implements FabContain // if this is the first time show first time activity Preferences prefs = Preferences.getPreferences(this); if (prefs.isFirstTime()) { - startActivity(new Intent(this, FirstTimeActivity.class)); + Intent intent = new Intent(this, CreateKeyActivity.class); + intent.putExtra(CreateKeyActivity.EXTRA_FIRST_TIME, true); + startActivity(intent); finish(); return; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java index 1bdec7b84..e21c5d510 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EmailEditText.java @@ -58,9 +58,10 @@ public class EmailEditText extends AutoCompleteTextView { } private void init() { - this.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); - this.addTextChangedListener(textWatcher); - removeFlag(); + setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); + reenableKeyboardSuggestions(); + + addTextChangedListener(textWatcher); initAdapter(); } @@ -104,7 +105,7 @@ public class EmailEditText extends AutoCompleteTextView { * Hack to re-enable keyboard auto correction in AutoCompleteTextView. * From http://stackoverflow.com/a/22512858 */ - private void removeFlag() { + private void reenableKeyboardSuggestions() { int inputType = getInputType(); inputType &= ~EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE; setRawInputType(inputType); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java index f086c5696..153bf2ff2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/NameEditText.java @@ -50,7 +50,7 @@ public class NameEditText extends AutoCompleteTextView { } private void init() { - removeFlag(); + reenableKeyboardSuggestions(); initAdapter(); } @@ -62,10 +62,10 @@ public class NameEditText extends AutoCompleteTextView { } /** - * Hack to re-enable keyboard auto correction in AutoCompleteTextView. + * Hack to re-enable keyboard suggestions in AutoCompleteTextView. * From http://stackoverflow.com/a/22512858 */ - private void removeFlag() { + private void reenableKeyboardSuggestions() { int inputType = getInputType(); inputType &= ~EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE; setRawInputType(inputType); -- cgit v1.2.3 From cfef53be01f72da477d0cb66e40865d7dcd9b125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 19 Mar 2015 17:21:26 +0100 Subject: Remove on click on icon --- .../main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index eb484302c..ab76f693e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; +import android.view.View; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.Passphrase; @@ -72,6 +73,7 @@ public class CreateKeyActivity extends BaseActivity { if (mFirstTime) { setTitle(R.string.app_name); setActionBarIcon(R.drawable.ic_launcher); + mToolbar.setNavigationOnClickListener(null); } else { setTitle(R.string.title_manage_my_keys); } -- cgit v1.2.3 From 8d6d4328f23b527be9ea794433b3f160cd58e5a5 Mon Sep 17 00:00:00 2001 From: Kent Date: Fri, 20 Mar 2015 06:31:18 +0800 Subject: Implemented #1162: Invoke NFC in Advanced View - Extracted NFC code from ViewKeyActivity to NfcHelper to share code between classes - Changed the private anonymous Handler for NFC into a static private subclass, that uses WeakReference to avoid memory leaks - Added resources needed (retrieved from Graphics) for the NFC button inside ViewKeyAdvShareFragment. - Fixed the ripple boundary of the Share With... button to prevent it from bleeding to other buttons on the right (UX improvement) --- .../keychain/ui/ViewKeyActivity.java | 169 ++--------------- .../keychain/ui/ViewKeyAdvShareFragment.java | 21 ++- .../keychain/util/NfcHelper.java | 204 +++++++++++++++++++++ 3 files changed, 240 insertions(+), 154 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java (limited to 'OpenKeychain/src/main/java') 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 5834fa502..45ad944c4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -21,18 +21,12 @@ package org.sufficientlysecure.keychain.ui; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; -import android.annotation.TargetApi; import android.app.Activity; import android.app.ActivityOptions; import android.content.Intent; -import android.content.pm.PackageManager; import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; -import android.nfc.NdefMessage; -import android.nfc.NdefRecord; -import android.nfc.NfcAdapter; -import android.nfc.NfcEvent; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; @@ -40,7 +34,6 @@ import android.os.Handler; import android.os.Message; import android.os.Messenger; import android.provider.ContactsContract; -import android.provider.Settings; import android.support.v4.app.ActivityCompat; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; @@ -58,9 +51,7 @@ 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; @@ -84,6 +75,7 @@ import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.util.ExportHelper; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.NfcHelper; import org.sufficientlysecure.keychain.util.Preferences; import java.util.ArrayList; @@ -93,8 +85,8 @@ public class ViewKeyActivity extends BaseActivity implements LoaderManager.LoaderCallbacks { static final int REQUEST_QR_FINGERPRINT = 1; - static final int REQUEST_DELETE= 2; - static final int REQUEST_EXPORT= 3; + static final int REQUEST_DELETE = 2; + static final int REQUEST_EXPORT = 3; ExportHelper mExportHelper; ProviderHelper mProviderHelper; @@ -115,11 +107,7 @@ public class ViewKeyActivity extends BaseActivity implements private CardView mQrCodeLayout; // NFC - private NfcAdapter mNfcAdapter; - private NfcAdapter.CreateNdefMessageCallback mNdefCallback; - private NfcAdapter.OnNdefPushCompleteCallback mNdefCompleteCallback; - private byte[] mNfcKeyringBytes; - private static final int NFC_SENT = 1; + private NfcHelper mNfcHelper; private static final int LOADER_ID_UNIFIED = 0; @@ -256,7 +244,7 @@ public class ViewKeyActivity extends BaseActivity implements mActionNfc.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - invokeNfcBeam(); + mNfcHelper.invokeNfcBeam(); } }); @@ -264,7 +252,8 @@ public class ViewKeyActivity extends BaseActivity implements // or start new ones. getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); - initNfc(mDataUri); + mNfcHelper = new NfcHelper(this, mProviderHelper); + mNfcHelper.initNfc(mDataUri); startFragment(savedInstanceState, mDataUri); } @@ -375,41 +364,6 @@ public class ViewKeyActivity extends BaseActivity implements return true; } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private void invokeNfcBeam() { - // Check if device supports NFC - if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) { - Notify.createNotify(this, R.string.no_nfc_support, Notify.LENGTH_LONG, Notify.Style.ERROR).show(); - return; - } - // Check for available NFC Adapter - mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - if (mNfcAdapter == null || !mNfcAdapter.isEnabled()) { - Notify.createNotify(this, R.string.error_nfc_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() { - @Override - public void onAction() { - Intent intentSettings = new Intent(Settings.ACTION_NFC_SETTINGS); - startActivity(intentSettings); - } - }, R.string.menu_nfc_preferences).show(); - - return; - } - - if (!mNfcAdapter.isNdefPushEnabled()) { - Notify.createNotify(this, R.string.error_beam_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() { - @Override - public void onAction() { - Intent intentSettings = new Intent(Settings.ACTION_NFCSHARING_SETTINGS); - startActivity(intentSettings); - } - }, R.string.menu_beam_preferences).show(); - - return; - } - - mNfcAdapter.invokeBeam(this); - } private void scanQrCode() { Intent scanQrCode = new Intent(this, ImportKeysProxyActivity.class); @@ -426,7 +380,7 @@ public class ViewKeyActivity extends BaseActivity implements private void certifyImmediate() { Intent intent = new Intent(this, CertifyKeyActivity.class); - intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{mMasterKeyId}); + intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[] {mMasterKeyId}); startCertifyIntent(intent); } @@ -487,11 +441,11 @@ public class ViewKeyActivity extends BaseActivity implements HashMap data = providerHelper.getGenericData( baseUri, - new String[]{KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET}, - new int[]{ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER}); + new String[] {KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET}, + new int[] {ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER}); exportHelper.showExportKeysDialog( - new long[]{(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)}, + new long[] {(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)}, Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) != 0) ); } catch (ProviderHelper.NotFoundException e) { @@ -515,7 +469,7 @@ public class ViewKeyActivity extends BaseActivity implements // Create a new Messenger for the communication back Messenger messenger = new Messenger(returnHandler); DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, - new long[]{ mMasterKeyId }); + new long[] {mMasterKeyId}); deleteKeyDialog.show(getSupportFragmentManager(), "deleteKeyDialog"); } @@ -546,11 +500,11 @@ public class ViewKeyActivity extends BaseActivity implements return; } - if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK){ + if (requestCode == REQUEST_DELETE && resultCode == Activity.RESULT_OK) { deleteKey(); } - if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK){ + if (requestCode == REQUEST_EXPORT && resultCode == Activity.RESULT_OK) { exportToFile(mDataUri, mExportHelper, mProviderHelper); } @@ -572,7 +526,7 @@ public class ViewKeyActivity extends BaseActivity implements long keyId = new ProviderHelper(this) .getCachedPublicKeyRing(dataUri) .extractOrGetMasterKeyId(); - long[] encryptionKeyIds = new long[]{keyId}; + long[] encryptionKeyIds = new long[] {keyId}; Intent intent; if (text) { intent = new Intent(this, EncryptTextActivity.class); @@ -710,98 +664,9 @@ public class ViewKeyActivity extends BaseActivity implements loadTask.execute(); } - /** - * NFC: Initialize NFC sharing if OS and device supports it - */ - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - private void initNfc(final Uri dataUri) { - // check if NFC Beam is supported (>= Android 4.1) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - - // Implementation for the CreateNdefMessageCallback interface - mNdefCallback = new NfcAdapter.CreateNdefMessageCallback() { - @Override - public NdefMessage createNdefMessage(NfcEvent event) { - /* - * When a device receives a push with an AAR in it, the application specified in the AAR is - * guaranteed to run. The AAR overrides the tag dispatch system. You can add it back in to - * guarantee that this activity starts when receiving a beamed message. For now, this code - * uses the tag dispatch system. - */ - return new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME, - mNfcKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME)); - } - }; - - // Implementation for the OnNdefPushCompleteCallback interface - mNdefCompleteCallback = new NfcAdapter.OnNdefPushCompleteCallback() { - @Override - public void onNdefPushComplete(NfcEvent event) { - // A handler is needed to send messages to the activity when this - // callback occurs, because it happens from a binder thread - mNfcHandler.obtainMessage(NFC_SENT).sendToTarget(); - } - }; - - // Check for available NFC Adapter - mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - if (mNfcAdapter != null) { - /* - * Retrieve mNfcKeyringBytes here asynchronously (to not block the UI) - * and init nfc adapter afterwards. - * mNfcKeyringBytes can not be retrieved in createNdefMessage, because this process - * has no permissions to query the Uri. - */ - AsyncTask initTask = - new AsyncTask() { - protected Void doInBackground(Void... unused) { - try { - Uri blobUri = - KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); - mNfcKeyringBytes = (byte[]) mProviderHelper.getGenericData( - blobUri, - KeychainContract.KeyRingData.KEY_RING_DATA, - ProviderHelper.FIELD_TYPE_BLOB); - } catch (ProviderHelper.NotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - - // no AsyncTask return (Void) - return null; - } - - protected void onPostExecute(Void unused) { - // Register callback to set NDEF message - mNfcAdapter.setNdefPushMessageCallback(mNdefCallback, - ViewKeyActivity.this); - // Register callback to listen for message-sent success - mNfcAdapter.setOnNdefPushCompleteCallback(mNdefCompleteCallback, - ViewKeyActivity.this); - } - }; - - initTask.execute(); - } - } - } - - /** - * NFC: This handler receives a message from onNdefPushComplete - */ - private final Handler mNfcHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case NFC_SENT: - Notify.showNotify( - ViewKeyActivity.this, R.string.nfc_successful, Notify.Style.INFO); - break; - } - } - }; // These are the rows that we will retrieve. - static final String[] PROJECTION = new String[]{ + static final String[] PROJECTION = new String[] { KeychainContract.KeyRings._ID, KeychainContract.KeyRings.MASTER_KEY_ID, KeychainContract.KeyRings.USER_ID, @@ -1018,4 +883,4 @@ public class ViewKeyActivity extends BaseActivity implements public void onLoaderReset(Loader loader) { } -} +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java index 95a6faea9..29586ae9f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -52,6 +52,7 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.NfcHelper; import java.io.IOException; @@ -68,10 +69,12 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements private View mFingerprintClipboardButton; private View mKeyShareButton; private View mKeyClipboardButton; + private View mKeyNfcButton; private ImageButton mKeySafeSlingerButton; private View mKeyUploadButton; ProviderHelper mProviderHelper; + NfcHelper mNfcHelper; private static final int LOADER_ID_UNIFIED = 0; @@ -83,6 +86,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements View view = inflater.inflate(R.layout.view_key_adv_share_fragment, getContainer()); mProviderHelper = new ProviderHelper(ViewKeyAdvShareFragment.this.getActivity()); + mNfcHelper = new NfcHelper(getActivity(), mProviderHelper); mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint); mQrCode = (ImageView) view.findViewById(R.id.view_key_qr_code); @@ -90,6 +94,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share); mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard); mKeyShareButton = view.findViewById(R.id.view_key_action_key_share); + mKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc); mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard); mKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger); mKeyUploadButton = view.findViewById(R.id.view_key_action_upload); @@ -128,6 +133,14 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements share(mDataUri, mProviderHelper, false, true); } }); + + mKeyNfcButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mNfcHelper.invokeNfcBeam(); + } + }); + mKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -255,9 +268,12 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); + + // Prepare the NfcHelper + mNfcHelper.initNfc(mDataUri); } - static final String[] UNIFIED_PROJECTION = new String[]{ + static final String[] UNIFIED_PROJECTION = new String[] { KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, KeyRings.USER_ID, KeyRings.FINGERPRINT, KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.IS_EXPIRED, @@ -362,4 +378,5 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements startActivityForResult(uploadIntent, 0); } -} + +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java new file mode 100644 index 000000000..bae42d965 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java @@ -0,0 +1,204 @@ +package org.sufficientlysecure.keychain.util; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.nfc.NfcEvent; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Handler; +import android.os.Message; +import android.provider.Settings; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.util.Notify; + +import java.lang.ref.WeakReference; + +/** + * This class contains NFC functionality that can be shared across Fragments or Activities. + *

+ * Created on Mar 20, 2015. + * + * @author Kent + */ + +public class NfcHelper { + + private Activity mActivity; + private ProviderHelper mProviderHelper; + + /** + * NFC: This handler receives a message from onNdefPushComplete + */ + private static NfcHandler mNfcHandler; + + private NfcAdapter mNfcAdapter; + private NfcAdapter.CreateNdefMessageCallback mNdefCallback; + private NfcAdapter.OnNdefPushCompleteCallback mNdefCompleteCallback; + private byte[] mNfcKeyringBytes; + private static final int NFC_SENT = 1; + + /** + * Initializes the NfcHelper. + */ + public NfcHelper(final Activity activity, final ProviderHelper providerHelper) { + mActivity = activity; + mProviderHelper = providerHelper; + + mNfcHandler = new NfcHandler(mActivity); + } + + /** + * Return true if the NFC Adapter of this Helper has any features enabled. + * + * @return true if this NFC Adapter has any features enabled + */ + public boolean isEnabled() { + return mNfcAdapter.isEnabled(); + } + + /** + * NFC: Initialize NFC sharing if OS and device supports it + */ + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + public void initNfc(final Uri dataUri) { + // check if NFC Beam is supported (>= Android 4.1) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + + // Implementation for the CreateNdefMessageCallback interface + mNdefCallback = new NfcAdapter.CreateNdefMessageCallback() { + @Override + public NdefMessage createNdefMessage(NfcEvent event) { + /* + * When a device receives a push with an AAR in it, the application specified in the AAR is + * guaranteed to run. The AAR overrides the tag dispatch system. You can add it back in to + * guarantee that this activity starts when receiving a beamed message. For now, this code + * uses the tag dispatch system. + */ + return new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME, + mNfcKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME)); + } + }; + + // Implementation for the OnNdefPushCompleteCallback interface + mNdefCompleteCallback = new NfcAdapter.OnNdefPushCompleteCallback() { + @Override + public void onNdefPushComplete(NfcEvent event) { + // A handler is needed to send messages to the activity when this + // callback occurs, because it happens from a binder thread + mNfcHandler.obtainMessage(NFC_SENT).sendToTarget(); + } + }; + + // Check for available NFC Adapter + mNfcAdapter = NfcAdapter.getDefaultAdapter(mActivity); + if (mNfcAdapter != null) { + /* + * Retrieve mNfcKeyringBytes here asynchronously (to not block the UI) + * and init nfc adapter afterwards. + * mNfcKeyringBytes can not be retrieved in createNdefMessage, because this process + * has no permissions to query the Uri. + */ + AsyncTask initTask = + new AsyncTask() { + protected Void doInBackground(Void... unused) { + try { + Uri blobUri = + KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); + mNfcKeyringBytes = (byte[]) mProviderHelper.getGenericData( + blobUri, + KeychainContract.KeyRingData.KEY_RING_DATA, + ProviderHelper.FIELD_TYPE_BLOB); + } catch (ProviderHelper.NotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + + // no AsyncTask return (Void) + return null; + } + + protected void onPostExecute(Void unused) { + // Register callback to set NDEF message + mNfcAdapter.setNdefPushMessageCallback(mNdefCallback, + mActivity); + // Register callback to listen for message-sent success + mNfcAdapter.setOnNdefPushCompleteCallback(mNdefCompleteCallback, + mActivity); + } + }; + + initTask.execute(); + } + } + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public void invokeNfcBeam() { + // Check if device supports NFC + if (!mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) { + Notify.createNotify(mActivity, R.string.no_nfc_support, Notify.LENGTH_LONG, Notify.Style.ERROR).show(); + return; + } + // Check for available NFC Adapter + mNfcAdapter = NfcAdapter.getDefaultAdapter(mActivity); + if (mNfcAdapter == null || !mNfcAdapter.isEnabled()) { + Notify.createNotify(mActivity, R.string.error_nfc_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() { + @Override + public void onAction() { + Intent intentSettings = new Intent(Settings.ACTION_NFC_SETTINGS); + mActivity.startActivity(intentSettings); + } + }, R.string.menu_nfc_preferences).show(); + + return; + } + + if (!mNfcAdapter.isNdefPushEnabled()) { + Notify.createNotify(mActivity, R.string.error_beam_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() { + @Override + public void onAction() { + Intent intentSettings = new Intent(Settings.ACTION_NFCSHARING_SETTINGS); + mActivity.startActivity(intentSettings); + } + }, R.string.menu_beam_preferences).show(); + + return; + } + + mNfcAdapter.invokeBeam(mActivity); + } + + /** + * A static subclass of {@link Handler} with a {@link WeakReference} to an {@link Activity} to avoid memory leaks. + */ + private static class NfcHandler extends Handler { + private final WeakReference mActivityReference; + + public NfcHandler(Activity activity) { + mActivityReference = new WeakReference<>(activity); + } + + @Override + public void handleMessage(Message msg) { + Activity activity = mActivityReference.get(); + + if (activity != null) { + switch (msg.what) { + case NFC_SENT: + Notify.showNotify( + activity, R.string.nfc_successful, Notify.Style.INFO); + break; + } + } + } + } + +} \ No newline at end of file -- cgit v1.2.3 From e0a5f1a0d44d49afffb1c5df1420431f39586c55 Mon Sep 17 00:00:00 2001 From: Kent Date: Fri, 20 Mar 2015 12:24:06 +0800 Subject: Removed create and added GPLv3 header --- .../sufficientlysecure/keychain/util/NfcHelper.java | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java index bae42d965..3d225eb04 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2014 Vincent Breitmoser + * + * 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.util; import android.annotation.TargetApi; @@ -24,10 +41,6 @@ import java.lang.ref.WeakReference; /** * This class contains NFC functionality that can be shared across Fragments or Activities. - *

- * Created on Mar 20, 2015. - * - * @author Kent */ public class NfcHelper { -- cgit v1.2.3 From 50913d0ff1f29d4d32c36b1924b20fc8ef3a76bc Mon Sep 17 00:00:00 2001 From: Kent Date: Fri, 20 Mar 2015 12:38:16 +0800 Subject: Updated GNU header --- .../src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java index 3d225eb04..a65576613 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java @@ -1,5 +1,6 @@ /* - * Copyright (C) 2014 Vincent Breitmoser + * Copyright (C) 2013-2014 Dominik Schürmann + * Copyright (C) 2015 Kent Nguyen * * 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 -- cgit v1.2.3