aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org
diff options
context:
space:
mode:
authorDaniel Albert <albert_daniel@t-online.de>2014-07-16 18:49:16 +0200
committerDaniel Albert <albert_daniel@t-online.de>2014-07-16 18:49:16 +0200
commitd63534d6559f846b670f07bcc99fdd85ebe9cb3a (patch)
tree85d0135e80668347f5438ef4f85e134049491e8c /OpenKeychain/src/main/java/org
parente375cde7e1a09df33c65a44ba57f3f75f2f98b15 (diff)
parent82af9672fdc7f548eb801c29d123c824ea286cdc (diff)
downloadopen-keychain-d63534d6559f846b670f07bcc99fdd85ebe9cb3a.tar.gz
open-keychain-d63534d6559f846b670f07bcc99fdd85ebe9cb3a.tar.bz2
open-keychain-d63534d6559f846b670f07bcc99fdd85ebe9cb3a.zip
Merge remote-tracking branch 'upstream/master'
Conflicts: OpenKeychain-Test/src/test/resources/extern/OpenPGP-Haskell OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
Diffstat (limited to 'OpenKeychain/src/main/java/org')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java261
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java93
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java20
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java28
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java17
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java27
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java59
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/KeyringTestingHelper.java56
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/PgpVerifyTestingHelper.java49
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/ProviderHelperStub.java22
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/TestDataUtil.java44
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/package-info.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java187
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java33
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java77
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java76
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java466
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java12
36 files changed, 728 insertions, 906 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index 86bc3fa5b..33ab52bca 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -69,6 +69,7 @@ public final class Constants {
public static final String KEY_SERVERS = "keyServers";
public static final String KEY_SERVERS_DEFAULT_VERSION = "keyServersDefaultVersion";
public static final String CONCEAL_PGP_APPLICATION = "concealPgpApplication";
+ public static final String FIRST_TIME = "firstTime";
}
public static final class Defaults {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
index fd8267a59..e55c14a2a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
@@ -139,6 +139,16 @@ public class Preferences {
editor.commit();
}
+ public boolean getFirstTime() {
+ return mSharedPreferences.getBoolean(Constants.Pref.FIRST_TIME, true);
+ }
+
+ public void setFirstTime(boolean value) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putBoolean(Constants.Pref.FIRST_TIME, value);
+ editor.commit();
+ }
+
public String[] getKeyServers() {
String rawData = mSharedPreferences.getString(Constants.Pref.KEY_SERVERS,
Constants.Defaults.KEY_SERVERS);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
index 0a49cb629..30e93f957 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
@@ -250,7 +250,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
mHashCode = key.hashCode();
- mPrimaryUserId = key.getPrimaryUserId();
+ mPrimaryUserId = key.getPrimaryUserIdWithFallback();
mUserIds = key.getUnorderedUserIds();
// if there was no user id flagged as primary, use the first one
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
index 47b827677..129ffba3e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/KeyRing.java
@@ -22,8 +22,10 @@ public abstract class KeyRing {
abstract public String getPrimaryUserId() throws PgpGeneralException;
- public String[] getSplitPrimaryUserId() throws PgpGeneralException {
- return splitUserId(getPrimaryUserId());
+ abstract public String getPrimaryUserIdWithFallback() throws PgpGeneralException;
+
+ public String[] getSplitPrimaryUserIdWithFallback() throws PgpGeneralException {
+ return splitUserId(getPrimaryUserIdWithFallback());
}
abstract public boolean isRevoked() throws PgpGeneralException;
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 a5ccfbd3b..db9e2c6c6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -258,7 +258,7 @@ public class PgpDecryptVerify {
continue;
}
// get subkey which has been used for this encryption packet
- secretEncryptionKey = secretKeyRing.getSubKey(encData.getKeyID());
+ secretEncryptionKey = secretKeyRing.getSecretKey(encData.getKeyID());
if (secretEncryptionKey == null) {
// continue with the next packet in the while loop
continue;
@@ -393,7 +393,7 @@ public class PgpDecryptVerify {
signingRing = mProviderHelper.getWrappedPublicKeyRing(
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
);
- signingKey = signingRing.getSubkey(sigKeyId);
+ signingKey = signingRing.getPublicKey(sigKeyId);
signatureIndex = i;
} catch (ProviderHelper.NotFoundException e) {
Log.d(Constants.TAG, "key not found!");
@@ -409,7 +409,7 @@ public class PgpDecryptVerify {
signatureResultBuilder.knownKey(true);
signatureResultBuilder.keyId(signingRing.getMasterKeyId());
try {
- signatureResultBuilder.userId(signingRing.getPrimaryUserId());
+ signatureResultBuilder.userId(signingRing.getPrimaryUserIdWithFallback());
} catch(PgpGeneralException e) {
Log.d(Constants.TAG, "No primary user id in key " + signingRing.getMasterKeyId());
}
@@ -578,7 +578,7 @@ public class PgpDecryptVerify {
signingRing = mProviderHelper.getWrappedPublicKeyRing(
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
);
- signingKey = signingRing.getSubkey(sigKeyId);
+ signingKey = signingRing.getPublicKey(sigKeyId);
signatureIndex = i;
} catch (ProviderHelper.NotFoundException e) {
Log.d(Constants.TAG, "key not found!");
@@ -596,7 +596,7 @@ public class PgpDecryptVerify {
signatureResultBuilder.knownKey(true);
signatureResultBuilder.keyId(signingRing.getMasterKeyId());
try {
- signatureResultBuilder.userId(signingRing.getPrimaryUserId());
+ signatureResultBuilder.userId(signingRing.getPrimaryUserIdWithFallback());
} catch(PgpGeneralException e) {
Log.d(Constants.TAG, "No primary user id in key " + signingRing.getMasterKeyId());
}
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 9a08290e4..bd8a9201e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -65,10 +65,8 @@ import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.util.Arrays;
-import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
-import java.util.TimeZone;
/**
* This class is the single place where ALL operations that actually modify a PGP public or secret
@@ -104,11 +102,12 @@ public class PgpKeyOperation {
}
/** Creates new secret key. */
- private PGPKeyPair createKey(int algorithmChoice, int keySize) throws PgpGeneralMsgIdException {
+ private PGPKeyPair createKey(int algorithmChoice, int keySize, OperationLog log, int indent) {
try {
if (keySize < 512) {
- throw new PgpGeneralMsgIdException(R.string.error_key_size_minimum512bit);
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_KEYSIZE_512, indent);
+ return null;
}
int algorithm;
@@ -143,7 +142,8 @@ public class PgpKeyOperation {
}
default: {
- throw new PgpGeneralMsgIdException(R.string.error_unknown_algorithm_choice);
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_UNKNOWN_ALGO, indent);
+ return null;
}
}
@@ -157,7 +157,9 @@ public class PgpKeyOperation {
} catch(InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
} catch(PGPException e) {
- throw new PgpGeneralMsgIdException(R.string.msg_mf_error_pgp, e);
+ Log.e(Constants.TAG, "internal pgp error", e);
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
+ return null;
}
}
@@ -166,20 +168,36 @@ public class PgpKeyOperation {
try {
- log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_KEYID, indent);
+ log.add(LogLevel.START, LogType.MSG_CR, indent);
indent += 1;
updateProgress(R.string.progress_building_key, 0, 100);
- if (saveParcel.addSubKeys == null || saveParcel.addSubKeys.isEmpty()) {
+ if (saveParcel.mAddSubKeys.isEmpty()) {
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_MASTER, indent);
return null;
}
- SubkeyAdd add = saveParcel.addSubKeys.remove(0);
- PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize);
+ if (saveParcel.mAddUserIds.isEmpty()) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_USER_ID, indent);
+ return null;
+ }
+
+ SubkeyAdd add = saveParcel.mAddSubKeys.remove(0);
+ if ((add.mFlags & KeyFlags.CERTIFY_OTHER) != KeyFlags.CERTIFY_OTHER) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_CERTIFY, indent);
+ return null;
+ }
if (add.mAlgorithm == Constants.choice.algorithm.elgamal) {
- throw new PgpGeneralMsgIdException(R.string.error_master_key_must_not_be_el_gamal);
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_MASTER_ELGAMAL, indent);
+ return null;
+ }
+
+ PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
+
+ // return null if this failed (an error will already have been logged by createKey)
+ if (keyPair == null) {
+ return null;
}
// define hashing and signing algos
@@ -195,17 +213,15 @@ public class PgpKeyOperation {
PGPSecretKeyRing sKR = new PGPSecretKeyRing(
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
- return internal(sKR, masterSecretKey, saveParcel, "", log, indent);
+ return internal(sKR, masterSecretKey, add.mFlags, saveParcel, "", log, indent);
} catch (PGPException e) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
Log.e(Constants.TAG, "pgp error encoding key", e);
return null;
} catch (IOException e) {
Log.e(Constants.TAG, "io error encoding key", e);
return null;
- } catch (PgpGeneralMsgIdException e) {
- Log.e(Constants.TAG, "pgp msg id error", e);
- return null;
}
}
@@ -257,11 +273,16 @@ public class PgpKeyOperation {
return null;
}
- return internal(sKR, masterSecretKey, saveParcel, passphrase, log, indent);
+ // read masterKeyFlags, and use the same as before.
+ // since this is the master key, this contains at least CERTIFY_OTHER
+ int masterKeyFlags = readKeyFlags(masterSecretKey.getPublicKey()) | KeyFlags.CERTIFY_OTHER;
+
+ return internal(sKR, masterSecretKey, masterKeyFlags, saveParcel, passphrase, log, indent);
}
private UncachedKeyRing internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
+ int masterKeyFlags,
SaveKeyringParcel saveParcel, String passphrase,
OperationLog log, int indent) {
@@ -289,7 +310,7 @@ public class PgpKeyOperation {
PGPPublicKey modifiedPublicKey = masterPublicKey;
// 2a. Add certificates for new user ids
- for (String userId : saveParcel.addUserIds) {
+ for (String userId : saveParcel.mAddUserIds) {
log.add(LogLevel.INFO, LogType.MSG_MF_UID_ADD, indent);
// this operation supersedes all previous binding and revocation certificates,
@@ -298,9 +319,10 @@ public class PgpKeyOperation {
Iterator<PGPSignature> it = modifiedPublicKey.getSignaturesForID(userId);
if (it != null) {
for (PGPSignature cert : new IterableIterator<PGPSignature>(it)) {
- // if it's not a self cert, never mind
if (cert.getKeyID() != masterPublicKey.getKeyID()) {
- continue;
+ // foreign certificate?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return null;
}
if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
|| cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
@@ -314,27 +336,31 @@ public class PgpKeyOperation {
}
// if it's supposed to be primary, we can do that here as well
- boolean isPrimary = saveParcel.changePrimaryUserId != null
- && userId.equals(saveParcel.changePrimaryUserId);
+ boolean isPrimary = saveParcel.mChangePrimaryUserId != null
+ && userId.equals(saveParcel.mChangePrimaryUserId);
// generate and add new certificate
PGPSignature cert = generateUserIdSignature(masterPrivateKey,
- masterPublicKey, userId, isPrimary);
- modifiedPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, cert);
+ masterPublicKey, userId, isPrimary, masterKeyFlags);
+ modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
}
// 2b. Add revocations for revoked user ids
- for (String userId : saveParcel.revokeUserIds) {
+ for (String userId : saveParcel.mRevokeUserIds) {
log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent);
- // a duplicate revocatin will be removed during canonicalization, so no need to
+ // a duplicate revocation will be removed during canonicalization, so no need to
// take care of that here.
PGPSignature cert = generateRevocationSignature(masterPrivateKey,
masterPublicKey, userId);
- modifiedPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, cert);
+ modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
}
// 3. If primary user id changed, generate new certificates for both old and new
- if (saveParcel.changePrimaryUserId != null) {
+ if (saveParcel.mChangePrimaryUserId != null) {
+
+ // keep track if we actually changed one
+ boolean ok = false;
log.add(LogLevel.INFO, LogType.MSG_MF_UID_PRIMARY, indent);
+ indent += 1;
// we work on the modifiedPublicKey here, to respect new or newly revoked uids
// noinspection unchecked
@@ -343,10 +369,11 @@ public class PgpKeyOperation {
PGPSignature currentCert = null;
// noinspection unchecked
for (PGPSignature cert : new IterableIterator<PGPSignature>(
- masterPublicKey.getSignaturesForID(userId))) {
- // if it's not a self cert, never mind
+ modifiedPublicKey.getSignaturesForID(userId))) {
if (cert.getKeyID() != masterPublicKey.getKeyID()) {
- continue;
+ // foreign certificate?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return null;
}
// we know from canonicalization that if there is any revocation here, it
// is valid and not superseded by a newer certification.
@@ -373,7 +400,7 @@ public class PgpKeyOperation {
// we definitely should not update certifications of revoked keys, so just leave it.
if (isRevoked) {
// revoked user ids cannot be primary!
- if (userId.equals(saveParcel.changePrimaryUserId)) {
+ if (userId.equals(saveParcel.mChangePrimaryUserId)) {
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
return null;
}
@@ -383,14 +410,16 @@ public class PgpKeyOperation {
// if this is~ the/a primary user id
if (currentCert.hasSubpackets() && currentCert.getHashedSubPackets().isPrimaryUserID()) {
// if it's the one we want, just leave it as is
- if (userId.equals(saveParcel.changePrimaryUserId)) {
+ if (userId.equals(saveParcel.mChangePrimaryUserId)) {
+ ok = true;
continue;
}
// otherwise, generate new non-primary certification
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert);
PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, false);
+ masterPrivateKey, masterPublicKey, userId, false, masterKeyFlags);
modifiedPublicKey = PGPPublicKey.addCertification(
modifiedPublicKey, userId, newCert);
continue;
@@ -399,20 +428,28 @@ public class PgpKeyOperation {
// if we are here, this is not currently a primary user id
// if it should be
- if (userId.equals(saveParcel.changePrimaryUserId)) {
+ if (userId.equals(saveParcel.mChangePrimaryUserId)) {
// add shiny new primary user id certificate
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_PRIMARY_NEW, indent);
modifiedPublicKey = PGPPublicKey.removeCertification(
modifiedPublicKey, userId, currentCert);
PGPSignature newCert = generateUserIdSignature(
- masterPrivateKey, masterPublicKey, userId, true);
+ masterPrivateKey, masterPublicKey, userId, true, masterKeyFlags);
modifiedPublicKey = PGPPublicKey.addCertification(
modifiedPublicKey, userId, newCert);
+ ok = true;
}
// user id is not primary and is not supposed to be - nothing to do here.
}
+ indent -= 1;
+
+ if (!ok) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NOEXIST_PRIMARY, indent);
+ return null;
+ }
}
// Update the secret key ring
@@ -423,9 +460,16 @@ public class PgpKeyOperation {
}
// 4a. For each subkey change, generate new subkey binding certificate
- for (SaveKeyringParcel.SubkeyChange change : saveParcel.changeSubKeys) {
+ for (SaveKeyringParcel.SubkeyChange change : saveParcel.mChangeSubKeys) {
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_CHANGE,
indent, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
+
+ // TODO allow changes in master key? this implies generating new user id certs...
+ if (change.mKeyId == masterPublicKey.getKeyID()) {
+ Log.e(Constants.TAG, "changing the master key not supported");
+ return null;
+ }
+
PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId);
if (sKey == null) {
log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_MISSING,
@@ -434,22 +478,45 @@ public class PgpKeyOperation {
}
PGPPublicKey pKey = sKey.getPublicKey();
- if (change.mExpiry != null && new Date(change.mExpiry).before(new Date())) {
+ // expiry must not be in the past
+ if (change.mExpiry != null && new Date(change.mExpiry*1000).before(new Date())) {
log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY,
indent + 1, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
return null;
}
- // generate and add new signature. we can be sloppy here and just leave the old one,
- // it will be removed during canonicalization
+ // keep old flags, or replace with new ones
+ int flags = change.mFlags == null ? readKeyFlags(pKey) : change.mFlags;
+ long expiry;
+ if (change.mExpiry == null) {
+ long valid = pKey.getValidSeconds();
+ expiry = valid == 0
+ ? 0
+ : pKey.getCreationTime().getTime() / 1000 + pKey.getValidSeconds();
+ } else {
+ expiry = change.mExpiry;
+ }
+
+ // drop all old signatures, they will be superseded by the new one
+ //noinspection unchecked
+ for (PGPSignature sig : new IterableIterator<PGPSignature>(pKey.getSignatures())) {
+ // special case: if there is a revocation, don't use expiry from before
+ if (change.mExpiry == null
+ && sig.getSignatureType() == PGPSignature.SUBKEY_REVOCATION) {
+ expiry = 0;
+ }
+ pKey = PGPPublicKey.removeCertification(pKey, sig);
+ }
+
+ // generate and add new signature
PGPSignature sig = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey,
- sKey, pKey, change.mFlags, change.mExpiry, passphrase);
+ sKey, pKey, flags, expiry, passphrase);
pKey = PGPPublicKey.addCertification(pKey, sig);
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
}
// 4b. For each subkey revocation, generate new subkey revocation certificate
- for (long revocation : saveParcel.revokeSubKeys) {
+ for (long revocation : saveParcel.mRevokeSubKeys) {
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_REVOKE,
indent, PgpKeyHelper.convertKeyIdToHex(revocation));
PGPSecretKey sKey = sKR.getSecretKey(revocation);
@@ -468,52 +535,51 @@ public class PgpKeyOperation {
}
// 5. Generate and add new subkeys
- for (SaveKeyringParcel.SubkeyAdd add : saveParcel.addSubKeys) {
- try {
-
- if (add.mExpiry != null && new Date(add.mExpiry).before(new Date())) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY, indent +1);
- return null;
- }
-
- log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);
+ for (SaveKeyringParcel.SubkeyAdd add : saveParcel.mAddSubKeys) {
- // generate a new secret key (privkey only for now)
- PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize);
-
- // add subkey binding signature (making this a sub rather than master key)
- PGPPublicKey pKey = keyPair.getPublicKey();
- PGPSignature cert = generateSubkeyBindingSignature(
- masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
- add.mFlags, add.mExpiry);
- pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
+ if (add.mExpiry != null && new Date(add.mExpiry*1000).before(new Date())) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_SUBKEY_PAST_EXPIRY, indent +1);
+ return null;
+ }
- PGPSecretKey sKey; {
- // define hashing and signing algos
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
- .build().get(HashAlgorithmTags.SHA1);
+ log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);
- // Build key encrypter and decrypter based on passphrase
- PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+ // generate a new secret key (privkey only for now)
+ PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
+ if(keyPair == null) {
+ return null;
+ }
- sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey,
- sha1Calc, false, keyEncryptor);
- }
+ // add subkey binding signature (making this a sub rather than master key)
+ PGPPublicKey pKey = keyPair.getPublicKey();
+ PGPSignature cert = generateSubkeyBindingSignature(
+ masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
+ add.mFlags, add.mExpiry == null ? 0 : add.mExpiry);
+ pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
+
+ PGPSecretKey sKey; {
+ // define hashing and signing algos
+ PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(HashAlgorithmTags.SHA1);
+
+ // Build key encrypter and decrypter based on passphrase
+ PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
+ PGPEncryptedData.CAST5, sha1Calc)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+
+ sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey,
+ sha1Calc, false, keyEncryptor);
+ }
- log.add(LogLevel.DEBUG, LogType.MSG_MF_SUBKEY_NEW_ID,
- indent+1, PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()));
+ log.add(LogLevel.DEBUG, LogType.MSG_MF_SUBKEY_NEW_ID,
+ indent+1, PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()));
- sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
- } catch (PgpGeneralMsgIdException e) {
- return null;
- }
}
// 6. If requested, change passphrase
- if (saveParcel.newPassphrase != null) {
+ if (saveParcel.mNewPassphrase != null) {
log.add(LogLevel.INFO, LogType.MSG_MF_PASSPHRASE, indent);
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build()
.get(HashAlgorithmTags.SHA1);
@@ -523,7 +589,7 @@ public class PgpKeyOperation {
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
PGPEncryptedData.CAST5, sha1Calc)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- saveParcel.newPassphrase.toCharArray());
+ saveParcel.mNewPassphrase.toCharArray());
sKR = PGPSecretKeyRing.copyWithNewPassword(sKR, keyDecryptor, keyEncryptorNew);
}
@@ -546,7 +612,7 @@ public class PgpKeyOperation {
}
private static PGPSignature generateUserIdSignature(
- PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary)
+ PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary, int flags)
throws IOException, PGPException, SignatureException {
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
pKey.getAlgorithm(), PGPUtil.SHA1)
@@ -558,6 +624,7 @@ public class PgpKeyOperation {
subHashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS);
subHashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS);
subHashedPacketsGen.setPrimaryUserID(false, primary);
+ subHashedPacketsGen.setKeyFlags(false, flags);
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey);
return sGen.generateCertification(userId, pKey);
@@ -599,7 +666,7 @@ 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, String passphrase)
throws IOException, PGPException, SignatureException {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
@@ -611,7 +678,7 @@ public class PgpKeyOperation {
private static PGPSignature generateSubkeyBindingSignature(
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
- PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, Long expiry)
+ PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, long expiry)
throws IOException, PGPException, SignatureException {
// date for signing
@@ -640,17 +707,9 @@ public class PgpKeyOperation {
hashedPacketsGen.setKeyFlags(false, flags);
}
- if (expiry != null) {
- Calendar creationDate = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- creationDate.setTime(pKey.getCreationTime());
-
- // (Just making sure there's no programming error here, this MUST have been checked above!)
- if (new Date(expiry).before(todayDate)) {
- throw new RuntimeException("Bad subkey creation date, this is a bug!");
- }
- hashedPacketsGen.setKeyExpirationTime(false, expiry - creationDate.getTimeInMillis());
- } else {
- hashedPacketsGen.setKeyExpirationTime(false, 0);
+ if (expiry > 0) {
+ long creationTime = pKey.getCreationTime().getTime() / 1000;
+ hashedPacketsGen.setKeyExpirationTime(false, expiry - creationTime);
}
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
@@ -665,4 +724,22 @@ public class PgpKeyOperation {
}
+ /** Returns all flags valid for this key.
+ *
+ * This method does not do any validity checks on the signature, so it should not be used on
+ * a non-canonicalized key!
+ *
+ */
+ private static int readKeyFlags(PGPPublicKey key) {
+ int flags = 0;
+ //noinspection unchecked
+ for(PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
+ if (!sig.hasSubpackets()) {
+ continue;
+ }
+ flags |= sig.getHashedSubPackets().getKeyFlags();
+ }
+ return flags;
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index 441e2762a..9ddfd3405 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -81,6 +81,10 @@ public class UncachedKeyRing {
return new UncachedPublicKey(mRing.getPublicKey());
}
+ public UncachedPublicKey getPublicKey(long keyId) {
+ return new UncachedPublicKey(mRing.getPublicKey(keyId));
+ }
+
public Iterator<UncachedPublicKey> getPublicKeys() {
final Iterator<PGPPublicKey> it = mRing.getPublicKeys();
return new Iterator<UncachedPublicKey>() {
@@ -558,7 +562,7 @@ public class UncachedKeyRing {
// make sure the certificate checks out
try {
cert.init(masterKey);
- if (!cert.verifySignature(key)) {
+ if (!cert.verifySignature(masterKey, key)) {
log.add(LogLevel.WARN, LogType.MSG_KC_SUB_REVOKE_BAD, indent);
badCerts += 1;
continue;
@@ -744,8 +748,12 @@ public class UncachedKeyRing {
}
- log.add(LogLevel.DEBUG, LogType.MSG_MG_FOUND_NEW,
- indent, Integer.toString(newCerts));
+ if (newCerts > 0) {
+ log.add(LogLevel.DEBUG, LogType.MSG_MG_FOUND_NEW, indent,
+ Integer.toString(newCerts));
+ } else {
+ log.add(LogLevel.DEBUG, LogType.MSG_MG_UNCHANGED, indent);
+ }
return new UncachedKeyRing(result);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java
index 33db7771b..ef5aa8e86 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java
@@ -9,6 +9,7 @@ import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.IterableIterator;
+import org.sufficientlysecure.keychain.util.Log;
import java.security.SignatureException;
import java.util.ArrayList;
@@ -44,14 +45,19 @@ public class UncachedPublicKey {
}
public Date getExpiryTime() {
- Date creationDate = getCreationTime();
- if (mPublicKey.getValidDays() == 0) {
+ long seconds = mPublicKey.getValidSeconds();
+ if (seconds > Integer.MAX_VALUE) {
+ Log.e(Constants.TAG, "error, expiry time too large");
+ return null;
+ }
+ if (seconds == 0) {
// no expiry
return null;
}
+ Date creationDate = getCreationTime();
Calendar calendar = GregorianCalendar.getInstance();
calendar.setTime(creationDate);
- calendar.add(Calendar.DATE, mPublicKey.getValidDays());
+ calendar.add(Calendar.SECOND, (int) seconds);
return calendar.getTime();
}
@@ -77,26 +83,76 @@ public class UncachedPublicKey {
return mPublicKey.getBitStrength();
}
+ /** Returns the primary user id, as indicated by the public key's self certificates.
+ *
+ * This is an expensive operation, since potentially a lot of certificates (and revocations)
+ * have to be checked, and even then the result is NOT guaranteed to be constant through a
+ * canonicalization operation.
+ *
+ * Returns null if there is no primary user id (as indicated by certificates)
+ *
+ */
public String getPrimaryUserId() {
+ String found = null;
+ PGPSignature foundSig = null;
for (String userId : new IterableIterator<String>(mPublicKey.getUserIDs())) {
+ PGPSignature revocation = null;
+
for (PGPSignature sig : new IterableIterator<PGPSignature>(mPublicKey.getSignaturesForID(userId))) {
- if (sig.getHashedSubPackets() != null
- && sig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.PRIMARY_USER_ID)) {
- try {
+ try {
+
+ // if this is a revocation, this is not the user id
+ if (sig.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
+ // make sure it's actually valid
+ sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider(
+ Constants.BOUNCY_CASTLE_PROVIDER_NAME), mPublicKey);
+ if (!sig.verifyCertification(userId, mPublicKey)) {
+ continue;
+ }
+ if (found != null && found.equals(userId)) {
+ found = null;
+ }
+ revocation = sig;
+ // this revocation may still be overridden by a newer cert
+ continue;
+ }
+
+ if (sig.getHashedSubPackets() != null && sig.getHashedSubPackets().isPrimaryUserID()) {
+ if (foundSig != null && sig.getCreationTime().before(foundSig.getCreationTime())) {
+ continue;
+ }
+ // ignore if there is a newer revocation for this user id
+ if (revocation != null && sig.getCreationTime().before(revocation.getCreationTime())) {
+ continue;
+ }
// make sure it's actually valid
sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME), mPublicKey);
if (sig.verifyCertification(userId, mPublicKey)) {
- return userId;
+ found = userId;
+ foundSig = sig;
+ // this one can't be relevant anymore at this point
+ revocation = null;
}
- } catch (Exception e) {
- // nothing bad happens, the key is just not considered the primary key id
}
- }
+ } catch (Exception e) {
+ // nothing bad happens, the key is just not considered the primary key id
+ }
}
}
- return null;
+ return found;
+ }
+
+ /**
+ * Returns primary user id if existing. If not, return first encountered user id.
+ */
+ public String getPrimaryUserIdWithFallback() {
+ String userId = getPrimaryUserId();
+ if (userId == null) {
+ userId = (String) mPublicKey.getUserIDs().next();
+ }
+ return userId;
}
public ArrayList<String> getUnorderedUserIds() {
@@ -186,6 +242,21 @@ public class UncachedPublicKey {
return mPublicKey;
}
+ public Iterator<WrappedSignature> getSignatures() {
+ final Iterator<PGPSignature> it = mPublicKey.getSignatures();
+ return new Iterator<WrappedSignature>() {
+ public void remove() {
+ it.remove();
+ }
+ public WrappedSignature next() {
+ return new WrappedSignature(it.next());
+ }
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+ };
+ }
+
public Iterator<WrappedSignature> getSignaturesForId(String userId) {
final Iterator<PGPSignature> it = mPublicKey.getSignaturesForID(userId);
return new Iterator<WrappedSignature>() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java
index 6f3068261..a054255dc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedKeyRing.java
@@ -39,8 +39,12 @@ public abstract class WrappedKeyRing extends KeyRing {
}
public String getPrimaryUserId() throws PgpGeneralException {
- return (String) getRing().getPublicKey().getUserIDs().next();
- };
+ return getPublicKey().getPrimaryUserId();
+ }
+
+ public String getPrimaryUserIdWithFallback() throws PgpGeneralException {
+ return getPublicKey().getPrimaryUserIdWithFallback();
+ }
public boolean isRevoked() throws PgpGeneralException {
// Is the master key revoked?
@@ -101,8 +105,16 @@ public abstract class WrappedKeyRing extends KeyRing {
abstract public IterableIterator<WrappedPublicKey> publicKeyIterator();
- public UncachedKeyRing getUncached() {
- return new UncachedKeyRing(getRing());
+ public WrappedPublicKey getPublicKey() {
+ return new WrappedPublicKey(this, getRing().getPublicKey());
+ }
+
+ public WrappedPublicKey getPublicKey(long id) {
+ return new WrappedPublicKey(this, getRing().getPublicKey(id));
+ }
+
+ public byte[] getEncoded() throws IOException {
+ return getRing().getEncoded();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java
index b2abf15a4..57d84072a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedPublicKeyRing.java
@@ -44,14 +44,6 @@ public class WrappedPublicKeyRing extends WrappedKeyRing {
getRing().encode(stream);
}
- public WrappedPublicKey getSubkey() {
- return new WrappedPublicKey(this, getRing().getPublicKey());
- }
-
- public WrappedPublicKey getSubkey(long id) {
- return new WrappedPublicKey(this, getRing().getPublicKey(id));
- }
-
/** Getter that returns the subkey that should be used for signing. */
WrappedPublicKey getEncryptionSubKey() throws PgpGeneralException {
PGPPublicKey key = getRing().getPublicKey(getEncryptId());
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java
index ef8044a9b..98ad2b706 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java
@@ -97,7 +97,7 @@ public class WrappedSecretKey extends WrappedPublicKey {
signatureGenerator.init(signatureType, mPrivateKey);
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- spGen.setSignerUserID(false, mRing.getPrimaryUserId());
+ spGen.setSignerUserID(false, mRing.getPrimaryUserIdWithFallback());
signatureGenerator.setHashedSubpackets(spGen.generate());
return signatureGenerator;
} catch(PGPException e) {
@@ -175,7 +175,7 @@ public class WrappedSecretKey extends WrappedPublicKey {
}
// get the master subkey (which we certify for)
- PGPPublicKey publicKey = publicKeyRing.getSubkey().getPublicKey();
+ PGPPublicKey publicKey = publicKeyRing.getPublicKey().getPublicKey();
// fetch public key ring, add the certification and return it
for (String userId : new IterableIterator<String>(userIds.iterator())) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
index c737b7c46..5cb24cf88 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
@@ -41,11 +41,11 @@ public class WrappedSecretKeyRing extends WrappedKeyRing {
return mRing;
}
- public WrappedSecretKey getSubKey() {
+ public WrappedSecretKey getSecretKey() {
return new WrappedSecretKey(this, mRing.getSecretKey());
}
- public WrappedSecretKey getSubKey(long id) {
+ public WrappedSecretKey getSecretKey(long id) {
return new WrappedSecretKey(this, mRing.getSecretKey(id));
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
index 196ac1dee..df19930c4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java
@@ -15,6 +15,7 @@ import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
import java.security.SignatureException;
+import java.util.ArrayList;
import java.util.Date;
/** OpenKeychain wrapper around PGPSignature objects.
@@ -55,12 +56,37 @@ public class WrappedSignature {
return mSig.getCreationTime();
}
+ public ArrayList<WrappedSignature> getEmbeddedSignatures() {
+ ArrayList<WrappedSignature> sigs = new ArrayList<WrappedSignature>();
+ if (!mSig.hasSubpackets()) {
+ return sigs;
+ }
+ try {
+ PGPSignatureList list;
+ list = mSig.getHashedSubPackets().getEmbeddedSignatures();
+ for(int i = 0; i < list.size(); i++) {
+ sigs.add(new WrappedSignature(list.get(i)));
+ }
+ list = mSig.getUnhashedSubPackets().getEmbeddedSignatures();
+ for(int i = 0; i < list.size(); i++) {
+ sigs.add(new WrappedSignature(list.get(i)));
+ }
+ } catch (PGPException e) {
+ // no matter
+ Log.e(Constants.TAG, "exception reading embedded signatures", e);
+ } catch (IOException e) {
+ // no matter
+ Log.e(Constants.TAG, "exception reading embedded signatures", e);
+ }
+ return sigs;
+ }
+
public byte[] getEncoded() throws IOException {
return mSig.getEncoded();
}
public boolean isRevocation() {
- return mSig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.REVOCATION_REASON);
+ return mSig.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION;
}
public boolean isPrimaryUserId() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java
index 48d40430a..34de0024d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/CachedPublicKeyRing.java
@@ -70,6 +70,10 @@ public class CachedPublicKeyRing extends KeyRing {
}
}
+ public String getPrimaryUserIdWithFallback() throws PgpGeneralException {
+ return getPrimaryUserId();
+ }
+
public boolean isRevoked() throws PgpGeneralException {
try {
Object data = mProviderHelper.getGenericData(mUri,
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index b5609a327..2d524f5b0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -199,7 +199,7 @@ public class ProviderHelper {
byte[] blob = cursor.getBlob(3);
if (blob != null) {
result.put(masterKeyId,
- new WrappedPublicKeyRing(blob, hasAnySecret, verified).getSubkey());
+ new WrappedPublicKeyRing(blob, hasAnySecret, verified).getPublicKey());
}
} while (cursor.moveToNext());
@@ -450,8 +450,7 @@ public class ProviderHelper {
if (cert.verifySignature(masterKey, userId)) {
item.trustedCerts.add(cert);
log(LogLevel.INFO, LogType.MSG_IP_UID_CERT_GOOD,
- PgpKeyHelper.convertKeyIdToHexShort(trustedKey.getKeyId()),
- trustedKey.getPrimaryUserId()
+ PgpKeyHelper.convertKeyIdToHexShort(trustedKey.getKeyId())
);
} else {
log(LogLevel.WARN, LogType.MSG_IP_UID_CERT_BAD);
@@ -670,7 +669,7 @@ public class ProviderHelper {
// If there is an old keyring, merge it
try {
- UncachedKeyRing oldPublicRing = getWrappedPublicKeyRing(masterKeyId).getUncached();
+ UncachedKeyRing oldPublicRing = getWrappedPublicKeyRing(masterKeyId).getUncachedKeyRing();
// Merge data from new public ring into the old one
publicRing = oldPublicRing.merge(publicRing, mLog, mIndent);
@@ -706,7 +705,7 @@ public class ProviderHelper {
// If there is a secret key, merge new data (if any) and save the key for later
UncachedKeyRing secretRing;
try {
- secretRing = getWrappedSecretKeyRing(publicRing.getMasterKeyId()).getUncached();
+ secretRing = getWrappedSecretKeyRing(publicRing.getMasterKeyId()).getUncachedKeyRing();
// Merge data from new public ring into secret one
secretRing = secretRing.merge(publicRing, mLog, mIndent);
@@ -754,10 +753,10 @@ public class ProviderHelper {
// If there is an old secret key, merge it.
try {
- UncachedKeyRing oldSecretRing = getWrappedSecretKeyRing(masterKeyId).getUncached();
+ UncachedKeyRing oldSecretRing = getWrappedSecretKeyRing(masterKeyId).getUncachedKeyRing();
// Merge data from new secret ring into old one
- secretRing = oldSecretRing.merge(secretRing, mLog, mIndent);
+ secretRing = secretRing.merge(oldSecretRing, mLog, mIndent);
// If this is null, there is an error in the log so we can just return
if (secretRing == null) {
@@ -791,9 +790,9 @@ public class ProviderHelper {
// Merge new data into public keyring as well, if there is any
UncachedKeyRing publicRing;
try {
- UncachedKeyRing oldPublicRing = getWrappedPublicKeyRing(masterKeyId).getUncached();
+ UncachedKeyRing oldPublicRing = getWrappedPublicKeyRing(masterKeyId).getUncachedKeyRing();
- // Merge data from new public ring into secret one
+ // Merge data from new secret ring into public one
publicRing = oldPublicRing.merge(secretRing, mLog, mIndent);
if (publicRing == null) {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog);
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 10faa8786..9a4cef2f1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -44,7 +44,6 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
-import org.sufficientlysecure.keychain.pgp.WrappedPublicKey;
import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.WrappedSecretKey;
import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
@@ -350,9 +349,9 @@ public class KeychainIntentService extends IntentService
providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 10, 95, 100));
// cache new passphrase
- if (saveParcel.newPassphrase != null) {
+ if (saveParcel.mNewPassphrase != null) {
PassphraseCacheService.addCachedPassphrase(this, ring.getMasterKeyId(),
- saveParcel.newPassphrase, ring.getPublicKey().getPrimaryUserId());
+ saveParcel.mNewPassphrase, ring.getPublicKey().getPrimaryUserIdWithFallback());
}
} catch (ProviderHelper.NotFoundException e) {
sendErrorToHandler(e);
@@ -546,7 +545,7 @@ public class KeychainIntentService extends IntentService
ProviderHelper providerHelper = new ProviderHelper(this);
WrappedPublicKeyRing publicRing = providerHelper.getWrappedPublicKeyRing(pubKeyId);
WrappedSecretKeyRing secretKeyRing = providerHelper.getWrappedSecretKeyRing(masterKeyId);
- WrappedSecretKey certificationKey = secretKeyRing.getSubKey();
+ WrappedSecretKey certificationKey = secretKeyRing.getSecretKey();
if(!certificationKey.unlock(signaturePassphrase)) {
throw new PgpGeneralException("Error extracting key (bad passphrase?)");
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index f868d931c..705d6afaf 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -9,6 +9,7 @@ import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -70,9 +71,6 @@ public class OperationResultParcel implements Parcelable {
mParameters = parameters;
mIndent = indent;
}
- public LogEntryParcel(LogLevel level, LogType type, Object... parameters) {
- this(level, type, 0, parameters);
- }
public LogEntryParcel(Parcel source) {
mLevel = LogLevel.values()[source.readInt()];
@@ -104,6 +102,15 @@ public class OperationResultParcel implements Parcelable {
}
};
+ @Override
+ public String toString() {
+ return "LogEntryParcel{" +
+ "mLevel=" + mLevel +
+ ", mType=" + mType +
+ ", mParameters=" + Arrays.toString(mParameters) +
+ ", mIndent=" + mIndent +
+ '}';
+ }
}
/** This is an enum of all possible log events.
@@ -235,9 +242,17 @@ public class OperationResultParcel implements Parcelable {
MSG_MG_HETEROGENEOUS (R.string.msg_mg_heterogeneous),
MSG_MG_NEW_SUBKEY (R.string.msg_mg_new_subkey),
MSG_MG_FOUND_NEW (R.string.msg_mg_found_new),
+ MSG_MG_UNCHANGED (R.string.msg_mg_unchanged),
// secret key create
- MSG_CR_ERROR_NO_MASTER (R.string.msg_mr),
+ MSG_CR (R.string.msg_cr),
+ MSG_CR_ERROR_NO_MASTER (R.string.msg_cr_error_no_master),
+ MSG_CR_ERROR_NO_USER_ID (R.string.msg_cr_error_no_user_id),
+ MSG_CR_ERROR_NO_CERTIFY (R.string.msg_cr_error_no_certify),
+ MSG_CR_ERROR_KEYSIZE_512 (R.string.msg_cr_error_keysize_512),
+ MSG_CR_ERROR_UNKNOWN_ALGO (R.string.msg_cr_error_unknown_algo),
+ MSG_CR_ERROR_INTERNAL_PGP (R.string.msg_cr_error_internal_pgp),
+ MSG_CR_ERROR_MASTER_ELGAMAL (R.string.msg_cr_error_master_elgamal),
// secret key modify
MSG_MF (R.string.msg_mr),
@@ -245,10 +260,13 @@ public class OperationResultParcel implements Parcelable {
MSG_MF_ERROR_FINGERPRINT (R.string.msg_mf_error_fingerprint),
MSG_MF_ERROR_KEYID (R.string.msg_mf_error_keyid),
MSG_MF_ERROR_INTEGRITY (R.string.msg_mf_error_integrity),
+ MSG_MF_ERROR_NOEXIST_PRIMARY (R.string.msg_mf_error_noexist_primary),
MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary),
MSG_MF_ERROR_PGP (R.string.msg_mf_error_pgp),
MSG_MF_ERROR_SIG (R.string.msg_mf_error_sig),
MSG_MF_PASSPHRASE (R.string.msg_mf_passphrase),
+ MSG_MF_PRIMARY_REPLACE_OLD (R.string.msg_mf_primary_replace_old),
+ MSG_MF_PRIMARY_NEW (R.string.msg_mf_primary_new),
MSG_MF_SUBKEY_CHANGE (R.string.msg_mf_subkey_change),
MSG_MF_SUBKEY_MISSING (R.string.msg_mf_subkey_missing),
MSG_MF_SUBKEY_NEW_ID (R.string.msg_mf_subkey_new_id),
@@ -314,6 +332,7 @@ public class OperationResultParcel implements Parcelable {
}
public void add(LogLevel level, LogType type, int indent) {
+ Log.d(Constants.TAG, type.toString());
mParcels.add(new OperationResultParcel.LogEntryParcel(level, type, indent, (Object[]) null));
}
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 72c1a8f67..13d9b497f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -191,7 +191,7 @@ public class PassphraseCacheService extends Service {
Log.d(Constants.TAG, "Key has no passphrase! Caches and returns empty passphrase!");
try {
- addCachedPassphrase(this, keyId, "", key.getPrimaryUserId());
+ addCachedPassphrase(this, keyId, "", key.getPrimaryUserIdWithFallback());
} catch (PgpGeneralException e) {
Log.d(Constants.TAG, "PgpGeneralException occured");
}
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 a56095767..5e90b396e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
@@ -27,23 +27,19 @@ public class SaveKeyringParcel implements Parcelable {
// the key fingerprint, for safety. MUST be null for a new key.
public byte[] mFingerprint;
- public String newPassphrase;
+ public String mNewPassphrase;
- public ArrayList<String> addUserIds;
- public ArrayList<SubkeyAdd> addSubKeys;
+ public ArrayList<String> mAddUserIds;
+ public ArrayList<SubkeyAdd> mAddSubKeys;
- public ArrayList<SubkeyChange> changeSubKeys;
- public String changePrimaryUserId;
+ public ArrayList<SubkeyChange> mChangeSubKeys;
+ public String mChangePrimaryUserId;
- public ArrayList<String> revokeUserIds;
- public ArrayList<Long> revokeSubKeys;
+ public ArrayList<String> mRevokeUserIds;
+ public ArrayList<Long> mRevokeSubKeys;
public SaveKeyringParcel() {
- addUserIds = new ArrayList<String>();
- addSubKeys = new ArrayList<SubkeyAdd>();
- changeSubKeys = new ArrayList<SubkeyChange>();
- revokeUserIds = new ArrayList<String>();
- revokeSubKeys = new ArrayList<Long>();
+ reset();
}
public SaveKeyringParcel(long masterKeyId, byte[] fingerprint) {
@@ -52,6 +48,16 @@ public class SaveKeyringParcel implements Parcelable {
mFingerprint = fingerprint;
}
+ public void reset() {
+ mNewPassphrase = null;
+ mAddUserIds = new ArrayList<String>();
+ mAddSubKeys = new ArrayList<SubkeyAdd>();
+ mChangePrimaryUserId = null;
+ mChangeSubKeys = new ArrayList<SubkeyChange>();
+ mRevokeUserIds = new ArrayList<String>();
+ mRevokeSubKeys = new ArrayList<Long>();
+ }
+
// performance gain for using Parcelable here would probably be negligible,
// use Serializable instead.
public static class SubkeyAdd implements Serializable {
@@ -70,6 +76,7 @@ public class SaveKeyringParcel implements Parcelable {
public static class SubkeyChange implements Serializable {
public long mKeyId;
public Integer mFlags;
+ // this is a long unix timestamp, in seconds (NOT MILLISECONDS!)
public Long mExpiry;
public SubkeyChange(long keyId, Integer flags, Long expiry) {
mKeyId = keyId;
@@ -82,16 +89,16 @@ public class SaveKeyringParcel implements Parcelable {
mMasterKeyId = source.readInt() != 0 ? source.readLong() : null;
mFingerprint = source.createByteArray();
- newPassphrase = source.readString();
+ mNewPassphrase = source.readString();
- addUserIds = source.createStringArrayList();
- addSubKeys = (ArrayList<SubkeyAdd>) source.readSerializable();
+ mAddUserIds = source.createStringArrayList();
+ mAddSubKeys = (ArrayList<SubkeyAdd>) source.readSerializable();
- changeSubKeys = (ArrayList<SubkeyChange>) source.readSerializable();
- changePrimaryUserId = source.readString();
+ mChangeSubKeys = (ArrayList<SubkeyChange>) source.readSerializable();
+ mChangePrimaryUserId = source.readString();
- revokeUserIds = source.createStringArrayList();
- revokeSubKeys = (ArrayList<Long>) source.readSerializable();
+ mRevokeUserIds = source.createStringArrayList();
+ mRevokeSubKeys = (ArrayList<Long>) source.readSerializable();
}
@Override
@@ -102,16 +109,16 @@ public class SaveKeyringParcel implements Parcelable {
}
destination.writeByteArray(mFingerprint);
- destination.writeString(newPassphrase);
+ destination.writeString(mNewPassphrase);
- destination.writeStringList(addUserIds);
- destination.writeSerializable(addSubKeys);
+ destination.writeStringList(mAddUserIds);
+ destination.writeSerializable(mAddSubKeys);
- destination.writeSerializable(changeSubKeys);
- destination.writeString(changePrimaryUserId);
+ destination.writeSerializable(mChangeSubKeys);
+ destination.writeString(mChangePrimaryUserId);
- destination.writeStringList(revokeUserIds);
- destination.writeSerializable(revokeSubKeys);
+ destination.writeStringList(mRevokeUserIds);
+ destination.writeSerializable(mRevokeSubKeys);
}
public static final Creator<SaveKeyringParcel> CREATOR = new Creator<SaveKeyringParcel>() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/KeyringTestingHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/KeyringTestingHelper.java
deleted file mode 100644
index a565f0707..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/KeyringTestingHelper.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.sufficientlysecure.keychain.testsupport;
-
-import android.content.Context;
-
-import org.sufficientlysecure.keychain.pgp.NullProgressable;
-import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.OperationResults;
-
-import java.util.Collection;
-
-/**
- * Helper for tests of the Keyring import in ProviderHelper.
- */
-public class KeyringTestingHelper {
-
- private final Context context;
-
- public KeyringTestingHelper(Context robolectricContext) {
- this.context = robolectricContext;
- }
-
- public boolean addKeyring(Collection<String> blobFiles) throws Exception {
-
- ProviderHelper providerHelper = new ProviderHelper(context);
-
- byte[] data = TestDataUtil.readAllFully(blobFiles);
- UncachedKeyRing ring = UncachedKeyRing.decodeFromData(data);
- long masterKeyId = ring.getMasterKeyId();
-
- // Should throw an exception; key is not yet saved
- retrieveKeyAndExpectNotFound(providerHelper, masterKeyId);
-
- OperationResults.SaveKeyringResult saveKeyringResult = providerHelper.savePublicKeyRing(ring, new NullProgressable());
-
- boolean saveSuccess = saveKeyringResult.success();
-
- // Now re-retrieve the saved key. Should not throw an exception.
- providerHelper.getWrappedPublicKeyRing(masterKeyId);
-
- // A different ID should still fail
- retrieveKeyAndExpectNotFound(providerHelper, masterKeyId - 1);
-
- return saveSuccess;
- }
-
-
- private void retrieveKeyAndExpectNotFound(ProviderHelper providerHelper, long masterKeyId) {
- try {
- providerHelper.getWrappedPublicKeyRing(masterKeyId);
- throw new AssertionError("Was expecting the previous call to fail!");
- } catch (ProviderHelper.NotFoundException expectedException) {
- // good
- }
- }
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/PgpVerifyTestingHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/PgpVerifyTestingHelper.java
deleted file mode 100644
index 1ab5878cc..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/PgpVerifyTestingHelper.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.sufficientlysecure.keychain.testsupport;
-
-import android.content.Context;
-
-import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
-import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.util.InputData;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * For functional tests of PgpDecryptVerify
- */
-public class PgpVerifyTestingHelper {
-
- private final Context context;
-
- public PgpVerifyTestingHelper(Context robolectricContext) {
- this.context = robolectricContext;
- }
-
- public int doTestFile(String testFileName) throws Exception {
- ProviderHelper providerHelper = new ProviderHelperStub(context);
-
- PgpDecryptVerify.PassphraseCache passphraseCache = new PgpDecryptVerify.PassphraseCache() {
- public String getCachedPassphrase(long masterKeyId) {
- return "I am a passphrase";
- }
- };
-
- byte[] sampleInputBytes = TestDataUtil.readFully(getClass().getResourceAsStream(testFileName));
-
- InputStream sampleInput = new ByteArrayInputStream(sampleInputBytes);
-
- InputData data = new InputData(sampleInput, sampleInputBytes.length);
- OutputStream outStream = new ByteArrayOutputStream();
-
- PgpDecryptVerify verify = new PgpDecryptVerify.Builder(providerHelper, passphraseCache, data, outStream).build();
- PgpDecryptVerifyResult result = verify.execute();
-
- return result.getSignatureResult().getStatus();
- }
-
-
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/ProviderHelperStub.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/ProviderHelperStub.java
deleted file mode 100644
index c6d834bf9..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/ProviderHelperStub.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.sufficientlysecure.keychain.testsupport;
-
-import android.content.Context;
-import android.net.Uri;
-
-import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-
-/**
- * Created by art on 21/06/14.
- */
-class ProviderHelperStub extends ProviderHelper {
- public ProviderHelperStub(Context context) {
- super(context);
- }
-
- @Override
- public WrappedPublicKeyRing getWrappedPublicKeyRing(Uri id) throws NotFoundException {
- byte[] data = TestDataUtil.readFully(getClass().getResourceAsStream("/public-key-for-sample.blob"));
- return new WrappedPublicKeyRing(data, false, 0);
- }
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/TestDataUtil.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/TestDataUtil.java
deleted file mode 100644
index 9e6ede761..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/TestDataUtil.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.sufficientlysecure.keychain.testsupport;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collection;
-
-/**
- * Misc support functions. Would just use Guava / Apache Commons but
- * avoiding extra dependencies.
- */
-public class TestDataUtil {
- public static byte[] readFully(InputStream input) {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- appendToOutput(input, output);
- return output.toByteArray();
- }
-
- private static void appendToOutput(InputStream input, ByteArrayOutputStream output) {
- byte[] buffer = new byte[8192];
- int bytesRead;
- try {
- while ((bytesRead = input.read(buffer)) != -1) {
- output.write(buffer, 0, bytesRead);
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- public static byte[] readAllFully(Collection<String> inputResources) {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
-
- for (String inputResource : inputResources) {
- appendToOutput(getResourceAsStream(inputResource), output);
- }
- return output.toByteArray();
- }
-
-
- public static InputStream getResourceAsStream(String resourceName) {
- return TestDataUtil.class.getResourceAsStream(resourceName);
- }
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/package-info.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/package-info.java
deleted file mode 100644
index 1cc0f9a95..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/testsupport/package-info.java
+++ /dev/null
@@ -1,7 +0,0 @@
-/**
- * Test support classes.
- * This is only in main code because of gradle-Android Studio-robolectric issues. Having
- * classes in main code means IDE autocomplete, class detection, etc., all works.
- * TODO Move into test package when possible
- */
-package org.sufficientlysecure.keychain.testsupport;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
new file mode 100644
index 000000000..d2073d9a7
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.support.v7.app.ActionBarActivity;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Patterns;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.Button;
+import android.widget.EditText;
+
+import org.spongycastle.bcpg.sig.KeyFlags;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ContactHelper;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+
+import java.util.regex.Matcher;
+
+public class CreateKeyActivity extends ActionBarActivity {
+
+ AutoCompleteTextView nameEdit;
+ AutoCompleteTextView emailEdit;
+ EditText passphraseEdit;
+ Button createButton;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.create_key_activity);
+
+ nameEdit = (AutoCompleteTextView) findViewById(R.id.name);
+ emailEdit = (AutoCompleteTextView) findViewById(R.id.email);
+ passphraseEdit = (EditText) findViewById(R.id.passphrase);
+ createButton = (Button) findViewById(R.id.create_key_button);
+
+ emailEdit.setThreshold(1); // Start working from first character
+ emailEdit.setAdapter(
+ new ArrayAdapter<String>
+ (this, android.R.layout.simple_spinner_dropdown_item,
+ ContactHelper.getPossibleUserEmails(this)
+ )
+ );
+ emailEdit.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ String email = editable.toString();
+ if (email.length() > 0) {
+ Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email);
+ if (emailMatcher.matches()) {
+ emailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0,
+ R.drawable.uid_mail_ok, 0);
+ } else {
+ emailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0,
+ R.drawable.uid_mail_bad, 0);
+ }
+ } else {
+ // remove drawable if email is empty
+ emailEdit.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
+ }
+ }
+ });
+ nameEdit.setThreshold(1); // Start working from first character
+ nameEdit.setAdapter(
+ new ArrayAdapter<String>
+ (this, android.R.layout.simple_spinner_dropdown_item,
+ ContactHelper.getPossibleUserNames(this)
+ )
+ );
+
+ createButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ createKeyCheck();
+ }
+ });
+
+ }
+
+ private void createKeyCheck() {
+ if (isEditTextNotEmpty(this, nameEdit)
+ && isEditTextNotEmpty(this, emailEdit)
+ && isEditTextNotEmpty(this, passphraseEdit)) {
+ createKey();
+ }
+ }
+
+ private void createKey() {
+ Intent intent = new Intent(this, KeychainIntentService.class);
+ intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
+
+ // Message is received after importing is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
+ this,
+ getString(R.string.progress_importing),
+ ProgressDialog.STYLE_HORIZONTAL) {
+ public void handleMessage(Message message) {
+ // handle messages by standard KeychainIntentServiceHandler first
+ super.handleMessage(message);
+
+ if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
+ CreateKeyActivity.this.finish();
+ }
+ }
+ };
+
+ // fill values for this action
+ Bundle data = new Bundle();
+
+ SaveKeyringParcel parcel = new SaveKeyringParcel();
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.CERTIFY_OTHER, null));
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.SIGN_DATA, null));
+ parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, null));
+ String userId = nameEdit.getText().toString() + " <" + emailEdit.getText().toString() + ">";
+ parcel.mAddUserIds.add(userId);
+ parcel.mNewPassphrase = passphraseEdit.getText().toString();
+
+ // get selected key entries
+ data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, parcel);
+
+ intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+
+ saveHandler.showProgressDialog(this);
+
+ startService(intent);
+ }
+
+ /**
+ * Checks if text of given EditText is not empty. If it is empty an error is
+ * set and the EditText gets the focus.
+ *
+ * @param context
+ * @param editText
+ * @return true if EditText is not empty
+ */
+ private static boolean isEditTextNotEmpty(Context context, EditText editText) {
+ boolean output = true;
+ if (editText.getText().toString().length() == 0) {
+ editText.setError("empty!");
+ editText.requestFocus();
+ output = false;
+ } else {
+ editText.setError(null);
+ }
+
+ return output;
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java
index 51457cd45..70ccb8800 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java
@@ -280,7 +280,7 @@ public class EditKeyActivityOld extends ActionBarActivity implements EditorListe
Uri secretUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
WrappedSecretKeyRing keyRing = new ProviderHelper(this).getWrappedSecretKeyRing(secretUri);
- mMasterCanSign = keyRing.getSubKey().canCertify();
+ mMasterCanSign = keyRing.getSecretKey().canCertify();
for (WrappedSecretKey key : keyRing.secretKeyIterator()) {
// Turn into uncached instance
mKeys.add(key.getUncached());
@@ -288,7 +288,7 @@ public class EditKeyActivityOld extends ActionBarActivity implements EditorListe
}
boolean isSet = false;
- for (String userId : keyRing.getSubKey().getUserIds()) {
+ for (String userId : keyRing.getSecretKey().getUserIds()) {
Log.d(Constants.TAG, "Added userId " + userId);
if (!isSet) {
isSet = true;
@@ -556,7 +556,7 @@ public class EditKeyActivityOld extends ActionBarActivity implements EditorListe
saveParams.deletedKeys = mKeysView.getDeletedKeys();
saveParams.keysExpiryDates = getKeysExpiryDates(mKeysView);
saveParams.keysUsages = getKeysUsages(mKeysView);
- saveParams.newPassphrase = mNewPassphrase;
+ saveParams.mNewPassphrase = mNewPassphrase;
saveParams.oldPassphrase = mCurrentPassphrase;
saveParams.newKeys = toPrimitiveArray(mKeysView.getNewKeysArray());
saveParams.keys = getKeys(mKeysView);
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 94ca883d6..b41871a39 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -228,7 +228,7 @@ public class EditKeyFragment extends LoaderFragment implements
}
});
- mSubkeysAddedAdapter = new SubkeysAddedAdapter(getActivity(), mSaveKeyringParcel.addSubKeys);
+ mSubkeysAddedAdapter = new SubkeysAddedAdapter(getActivity(), mSaveKeyringParcel.mAddSubKeys);
mSubkeysAddedList.setAdapter(mSubkeysAddedAdapter);
// Prepare the loaders. Either re-connect with an existing ones,
@@ -298,7 +298,7 @@ public class EditKeyFragment extends LoaderFragment implements
Bundle data = message.getData();
// cache new returned passphrase!
- mSaveKeyringParcel.newPassphrase = data
+ mSaveKeyringParcel.mNewPassphrase = data
.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE);
}
}
@@ -320,19 +320,19 @@ public class EditKeyFragment extends LoaderFragment implements
switch (message.what) {
case EditUserIdDialogFragment.MESSAGE_CHANGE_PRIMARY_USER_ID:
// toggle
- if (mSaveKeyringParcel.changePrimaryUserId != null
- && mSaveKeyringParcel.changePrimaryUserId.equals(userId)) {
- mSaveKeyringParcel.changePrimaryUserId = null;
+ if (mSaveKeyringParcel.mChangePrimaryUserId != null
+ && mSaveKeyringParcel.mChangePrimaryUserId.equals(userId)) {
+ mSaveKeyringParcel.mChangePrimaryUserId = null;
} else {
- mSaveKeyringParcel.changePrimaryUserId = userId;
+ mSaveKeyringParcel.mChangePrimaryUserId = userId;
}
break;
case EditUserIdDialogFragment.MESSAGE_REVOKE:
// toggle
- if (mSaveKeyringParcel.revokeUserIds.contains(userId)) {
- mSaveKeyringParcel.revokeUserIds.remove(userId);
+ if (mSaveKeyringParcel.mRevokeUserIds.contains(userId)) {
+ mSaveKeyringParcel.mRevokeUserIds.remove(userId);
} else {
- mSaveKeyringParcel.revokeUserIds.add(userId);
+ mSaveKeyringParcel.mRevokeUserIds.add(userId);
}
break;
}
@@ -363,10 +363,10 @@ public class EditKeyFragment extends LoaderFragment implements
break;
case EditSubkeyDialogFragment.MESSAGE_REVOKE:
// toggle
- if (mSaveKeyringParcel.revokeSubKeys.contains(keyId)) {
- mSaveKeyringParcel.revokeSubKeys.remove(keyId);
+ if (mSaveKeyringParcel.mRevokeSubKeys.contains(keyId)) {
+ mSaveKeyringParcel.mRevokeSubKeys.remove(keyId);
} else {
- mSaveKeyringParcel.revokeSubKeys.add(keyId);
+ mSaveKeyringParcel.mRevokeSubKeys.add(keyId);
}
break;
}
@@ -450,10 +450,11 @@ public class EditKeyFragment extends LoaderFragment implements
}
private void save(String passphrase) {
- Log.d(Constants.TAG, "add userids to parcel: " + mUserIdsAddedAdapter.getDataAsStringList());
- Log.d(Constants.TAG, "mSaveKeyringParcel.newPassphrase: " + mSaveKeyringParcel.newPassphrase);
+ mSaveKeyringParcel.mAddUserIds = mUserIdsAddedAdapter.getDataAsStringList();
- mSaveKeyringParcel.addUserIds = mUserIdsAddedAdapter.getDataAsStringList();
+ Log.d(Constants.TAG, "mSaveKeyringParcel.mAddUserIds: " + mSaveKeyringParcel.mAddUserIds);
+ Log.d(Constants.TAG, "mSaveKeyringParcel.mNewPassphrase: " + mSaveKeyringParcel.mNewPassphrase);
+ Log.d(Constants.TAG, "mSaveKeyringParcel.mRevokeUserIds: " + mSaveKeyringParcel.mRevokeUserIds);
// Message is received after importing is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
@@ -509,4 +510,4 @@ public class EditKeyFragment extends LoaderFragment implements
// start service with intent
getActivity().startService(intent);
}
-} \ No newline at end of file
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
index 51963e963..dc0510189 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
@@ -198,7 +198,7 @@ public class EncryptAsymmetricFragment extends Fragment {
String[] userId;
try {
userId = mProviderHelper.getCachedPublicKeyRing(
- KeyRings.buildUnifiedKeyRingUri(mSecretKeyId)).getSplitPrimaryUserId();
+ KeyRings.buildUnifiedKeyRingUri(mSecretKeyId)).getSplitPrimaryUserIdWithFallback();
} catch (PgpGeneralException e) {
userId = null;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java
new file mode 100644
index 000000000..aa4120d2c
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.ActionBarActivity;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+
+import org.sufficientlysecure.keychain.R;
+
+public class FirstTimeActivity extends ActionBarActivity {
+
+ Button mCreateKey;
+ Button mImportKey;
+ Button mSkipSetup;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ setContentView(R.layout.first_time_activity);
+
+ mCreateKey = (Button) findViewById(R.id.first_time_create_key);
+ mImportKey = (Button) findViewById(R.id.first_time_import_key);
+ mSkipSetup = (Button) findViewById(R.id.first_time_cancel);
+
+ mSkipSetup.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(FirstTimeActivity.this, KeyListActivity.class);
+ startActivity(intent);
+ finish();
+ }
+ });
+
+ 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);
+ startActivity(intent);
+ finish();
+ }
+ });
+
+ mCreateKey.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(FirstTimeActivity.this, CreateKeyActivity.class);
+ startActivity(intent);
+ finish();
+ }
+ });
+
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
index 849576284..9cc623c83 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
@@ -32,8 +32,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Constants.choice.algorithm;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ExportHelper;
-import org.sufficientlysecure.keychain.helper.OtherHelper;
-import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
+import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
@@ -43,7 +42,6 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
-import java.util.ArrayList;
public class KeyListActivity extends DrawerActivity {
@@ -53,6 +51,15 @@ public class KeyListActivity extends DrawerActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ Preferences prefs = Preferences.getPreferences(this);
+ if (prefs.getFirstTime()) {
+ prefs.setFirstTime(false);
+ Intent intent = new Intent(this, FirstTimeActivity.class);
+ startActivity(intent);
+ finish();
+ return;
+ }
+
mExportHelper = new ExportHelper(this);
setContentView(R.layout.key_list_activity);
@@ -66,9 +73,10 @@ public class KeyListActivity extends DrawerActivity {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.key_list, menu);
- if(Constants.DEBUG) {
+ if (Constants.DEBUG) {
menu.findItem(R.id.menu_key_list_debug_read).setVisible(true);
menu.findItem(R.id.menu_key_list_debug_write).setVisible(true);
+ menu.findItem(R.id.menu_key_list_debug_first_time).setVisible(true);
}
return true;
@@ -85,10 +93,6 @@ public class KeyListActivity extends DrawerActivity {
createKey();
return true;
- case R.id.menu_key_list_create_expert:
- createKeyExpert();
- return true;
-
case R.id.menu_key_list_export:
mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true);
return true;
@@ -98,7 +102,7 @@ public class KeyListActivity extends DrawerActivity {
KeychainDatabase.debugRead(this);
AppMsg.makeText(this, "Restored from backup", AppMsg.STYLE_CONFIRM).show();
getContentResolver().notifyChange(KeychainContract.KeyRings.CONTENT_URI, null);
- } catch(IOException e) {
+ } catch (IOException e) {
Log.e(Constants.TAG, "IO Error", e);
AppMsg.makeText(this, "IO Error: " + e.getMessage(), AppMsg.STYLE_ALERT).show();
}
@@ -108,12 +112,18 @@ public class KeyListActivity extends DrawerActivity {
try {
KeychainDatabase.debugWrite(this);
AppMsg.makeText(this, "Backup successful", AppMsg.STYLE_CONFIRM).show();
- } catch(IOException e) {
+ } catch (IOException e) {
Log.e(Constants.TAG, "IO Error", e);
AppMsg.makeText(this, "IO Error: " + e.getMessage(), AppMsg.STYLE_ALERT).show();
}
return true;
+ case R.id.menu_key_list_debug_first_time:
+ Intent intent = new Intent(this, FirstTimeActivity.class);
+ startActivity(intent);
+ finish();
+ return true;
+
default:
return super.onOptionsItemSelected(item);
}
@@ -125,50 +135,8 @@ public class KeyListActivity extends DrawerActivity {
}
private void createKey() {
- Intent intent = new Intent(this, WizardActivity.class);
-// intent.setAction(EditKeyActivity.ACTION_CREATE_KEY);
-// intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true);
-// intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, ""); // show user id view
- startActivityForResult(intent, 0);
+ Intent intent = new Intent(this, CreateKeyActivity.class);
+ startActivity(intent);
}
- private void createKeyExpert() {
- Intent intent = new Intent(this, KeychainIntentService.class);
- intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
-
- // Message is received after importing is done in KeychainIntentService
- KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
- this,
- getString(R.string.progress_importing),
- ProgressDialog.STYLE_HORIZONTAL) {
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
- super.handleMessage(message);
- Bundle data = message.getData();
- // OtherHelper.logDebugBundle(data, "message reply");
- }
- };
-
- // fill values for this action
- Bundle data = new Bundle();
-
- SaveKeyringParcel parcel = new SaveKeyringParcel();
- parcel.addSubKeys.add(new SubkeyAdd(algorithm.rsa, 1024, KeyFlags.CERTIFY_OTHER, null));
- parcel.addSubKeys.add(new SubkeyAdd(algorithm.rsa, 1024, KeyFlags.SIGN_DATA, null));
- parcel.addUserIds.add("swagerinho");
- parcel.newPassphrase = "swag";
-
- // get selected key entries
- data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, parcel);
-
- intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
-
- saveHandler.showProgressDialog(this);
-
- startService(intent);
- }
} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java
index c7fffe263..cfdea0611 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java
@@ -149,8 +149,8 @@ public class ViewCertActivity extends ActionBarActivity
providerHelper.getWrappedPublicKeyRing(sig.getKeyId());
try {
- sig.init(signerRing.getSubkey());
- if (sig.verifySignature(signeeRing.getSubkey(), signeeUid)) {
+ sig.init(signerRing.getPublicKey());
+ if (sig.verifySignature(signeeRing.getPublicKey(), signeeUid)) {
mStatus.setText(R.string.cert_verify_ok);
mStatus.setTextColor(getResources().getColor(R.color.result_green));
} else {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java
deleted file mode 100644
index 601fc09f9..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.ui;
-
-import android.app.Activity;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v7.app.ActionBarActivity;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Patterns;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.ArrayAdapter;
-import android.widget.AutoCompleteTextView;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.RadioGroup;
-import android.widget.TextView;
-
-import org.sufficientlysecure.htmltextview.HtmlTextView;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.ContactHelper;
-import org.sufficientlysecure.keychain.util.Log;
-
-import java.util.regex.Matcher;
-
-
-public class WizardActivity extends ActionBarActivity {
-
- private State mCurrentState;
-
- // values for mCurrentScreen
- private enum State {
- START, CREATE_KEY, IMPORT_KEY, K9
- }
-
- public static final int REQUEST_CODE_IMPORT = 0x00007703;
-
- Button mBackButton;
- Button mNextButton;
- StartFragment mStartFragment;
- CreateKeyFragment mCreateKeyFragment;
- K9Fragment mK9Fragment;
-
- private static final String K9_PACKAGE = "com.fsck.k9";
- // private static final String K9_MARKET_INTENT_URI_BASE = "market://details?id=%s";
-// private static final Intent K9_MARKET_INTENT = new Intent(Intent.ACTION_VIEW, Uri.parse(
-// String.format(K9_MARKET_INTENT_URI_BASE, K9_PACKAGE)));
- private static final Intent K9_MARKET_INTENT = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/k9mail/k-9/releases/tag/4.904"));
-
- LinearLayout mProgressLayout;
- View mProgressLine;
- ProgressBar mProgressBar;
- ImageView mProgressImage;
- TextView mProgressText;
-
- /**
- * Checks if text of given EditText is not empty. If it is empty an error is
- * set and the EditText gets the focus.
- *
- * @param context
- * @param editText
- * @return true if EditText is not empty
- */
- private static boolean isEditTextNotEmpty(Context context, EditText editText) {
- boolean output = true;
- if (editText.getText().toString().length() == 0) {
- editText.setError("empty!");
- editText.requestFocus();
- output = false;
- } else {
- editText.setError(null);
- }
-
- return output;
- }
-
- public static class StartFragment extends Fragment {
- public static StartFragment newInstance() {
- StartFragment myFragment = new StartFragment();
-
- Bundle args = new Bundle();
- myFragment.setArguments(args);
-
- return myFragment;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.wizard_start_fragment,
- container, false);
- }
- }
-
- public static class CreateKeyFragment extends Fragment {
- public static CreateKeyFragment newInstance() {
- CreateKeyFragment myFragment = new CreateKeyFragment();
-
- Bundle args = new Bundle();
- myFragment.setArguments(args);
-
- return myFragment;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.wizard_create_key_fragment,
- container, false);
-
- final AutoCompleteTextView emailView = (AutoCompleteTextView) view.findViewById(R.id.email);
- emailView.setThreshold(1); // Start working from first character
- emailView.setAdapter(
- new ArrayAdapter<String>
- (getActivity(), android.R.layout.simple_spinner_dropdown_item,
- ContactHelper.getPossibleUserEmails(getActivity())
- )
- );
- emailView.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
- }
-
- @Override
- public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
- }
-
- @Override
- public void afterTextChanged(Editable editable) {
- String email = editable.toString();
- if (email.length() > 0) {
- Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email);
- if (emailMatcher.matches()) {
- emailView.setCompoundDrawablesWithIntrinsicBounds(0, 0,
- R.drawable.uid_mail_ok, 0);
- } else {
- emailView.setCompoundDrawablesWithIntrinsicBounds(0, 0,
- R.drawable.uid_mail_bad, 0);
- }
- } else {
- // remove drawable if email is empty
- emailView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
- }
- }
- });
- final AutoCompleteTextView nameView = (AutoCompleteTextView) view.findViewById(R.id.name);
- nameView.setThreshold(1); // Start working from first character
- nameView.setAdapter(
- new ArrayAdapter<String>
- (getActivity(), android.R.layout.simple_spinner_dropdown_item,
- ContactHelper.getPossibleUserNames(getActivity())
- )
- );
- return view;
- }
- }
-
- public static class K9Fragment extends Fragment {
- public static K9Fragment newInstance() {
- K9Fragment myFragment = new K9Fragment();
-
- Bundle args = new Bundle();
- myFragment.setArguments(args);
-
- return myFragment;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.wizard_k9_fragment,
- container, false);
-
- HtmlTextView text = (HtmlTextView) v
- .findViewById(R.id.wizard_k9_text);
- text.setHtmlFromString("Install K9. It's good for you! Here is a screenhot how to enable OK in K9: (TODO)", true);
-
- return v;
- }
-
- }
-
- /**
- * Loads new fragment
- *
- * @param fragment
- */
- private void loadFragment(Fragment fragment) {
- FragmentManager fragmentManager = getSupportFragmentManager();
- FragmentTransaction fragmentTransaction = fragmentManager
- .beginTransaction();
- fragmentTransaction.replace(R.id.wizard_container,
- fragment);
- fragmentTransaction.commit();
- }
-
- /**
- * Instantiate View and initialize fragments for this Activity
- */
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.wizard_activity);
- mBackButton = (Button) findViewById(R.id.wizard_back);
- mNextButton = (Button) findViewById(R.id.wizard_next);
-
- // progress layout
- mProgressLayout = (LinearLayout) findViewById(R.id.wizard_progress);
- mProgressLine = findViewById(R.id.wizard_progress_line);
- mProgressBar = (ProgressBar) findViewById(R.id.wizard_progress_progressbar);
- mProgressImage = (ImageView) findViewById(R.id.wizard_progress_image);
- mProgressText = (TextView) findViewById(R.id.wizard_progress_text);
-
- changeToState(State.START);
- }
-
- private enum ProgressState {
- WORKING, ENABLED, DISABLED, ERROR
- }
-
- private void showProgress(ProgressState state, String text) {
- switch (state) {
- case WORKING:
- mProgressBar.setVisibility(View.VISIBLE);
- mProgressImage.setVisibility(View.GONE);
- break;
- case ENABLED:
- mProgressBar.setVisibility(View.GONE);
- mProgressImage.setVisibility(View.VISIBLE);
-// mProgressImage.setImageDrawable(getResources().getDrawable(
-// R.drawable.status_enabled));
- break;
- case DISABLED:
- mProgressBar.setVisibility(View.GONE);
- mProgressImage.setVisibility(View.VISIBLE);
-// mProgressImage.setImageDrawable(getResources().getDrawable(
-// R.drawable.status_disabled));
- break;
- case ERROR:
- mProgressBar.setVisibility(View.GONE);
- mProgressImage.setVisibility(View.VISIBLE);
-// mProgressImage.setImageDrawable(getResources().getDrawable(
-// R.drawable.status_fail));
- break;
-
- default:
- break;
- }
- mProgressText.setText(text);
-
- mProgressLine.setVisibility(View.VISIBLE);
- mProgressLayout.setVisibility(View.VISIBLE);
- }
-
- private void hideProgress() {
- mProgressLine.setVisibility(View.GONE);
- mProgressLayout.setVisibility(View.GONE);
- }
-
- public void nextOnClick(View view) {
- // close keyboard
- if (getCurrentFocus() != null) {
- InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- inputManager.hideSoftInputFromWindow(getCurrentFocus()
- .getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
- }
-
- switch (mCurrentState) {
- case START: {
- RadioGroup radioGroup = (RadioGroup) findViewById(R.id.wizard_start_radio_group);
- int selectedId = radioGroup.getCheckedRadioButtonId();
- switch (selectedId) {
- case R.id.wizard_start_new_key: {
- changeToState(State.CREATE_KEY);
- break;
- }
- case R.id.wizard_start_import: {
- changeToState(State.IMPORT_KEY);
- break;
- }
- case R.id.wizard_start_skip: {
- finish();
- break;
- }
- }
-
- mBackButton.setText(R.string.btn_back);
- break;
- }
- case CREATE_KEY:
- EditText nameEdit = (EditText) findViewById(R.id.name);
- EditText emailEdit = (EditText) findViewById(R.id.email);
- EditText passphraseEdit = (EditText) findViewById(R.id.passphrase);
-
- if (isEditTextNotEmpty(this, nameEdit)
- && isEditTextNotEmpty(this, emailEdit)
- && isEditTextNotEmpty(this, passphraseEdit)) {
-
-// SaveKeyringParcel newKey = new SaveKeyringParcel();
-// newKey.addUserIds.add(nameEdit.getText().toString() + " <"
-// + emailEdit.getText().toString() + ">");
-
-
- AsyncTask<String, Boolean, Boolean> generateTask = new AsyncTask<String, Boolean, Boolean>() {
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
-
- showProgress(ProgressState.WORKING, "generating key...");
- }
-
- @Override
- protected Boolean doInBackground(String... params) {
- return true;
- }
-
- @Override
- protected void onPostExecute(Boolean result) {
- super.onPostExecute(result);
-
- if (result) {
- showProgress(ProgressState.ENABLED, "key generated successfully!");
-
- changeToState(State.K9);
- } else {
- showProgress(ProgressState.ERROR, "error in key gen");
- }
- }
-
- };
-
- generateTask.execute("");
- }
- break;
- case K9: {
- RadioGroup radioGroup = (RadioGroup) findViewById(R.id.wizard_k9_radio_group);
- int selectedId = radioGroup.getCheckedRadioButtonId();
- switch (selectedId) {
- case R.id.wizard_k9_install: {
- try {
- startActivity(K9_MARKET_INTENT);
- } catch (ActivityNotFoundException e) {
- Log.e(Constants.TAG, "Activity not found for: " + K9_MARKET_INTENT);
- }
- break;
- }
- case R.id.wizard_k9_skip: {
- finish();
- break;
- }
- }
-
- finish();
- break;
- }
- default:
- break;
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- switch (requestCode) {
- case REQUEST_CODE_IMPORT: {
- if (resultCode == Activity.RESULT_OK) {
- // imported now...
- changeToState(State.K9);
- } else {
- // back to start
- changeToState(State.START);
- }
- break;
- }
-
- default: {
- super.onActivityResult(requestCode, resultCode, data);
-
- break;
- }
- }
- }
-
- public void backOnClick(View view) {
- switch (mCurrentState) {
- case START:
- finish();
- break;
- case CREATE_KEY:
- changeToState(State.START);
- break;
- case IMPORT_KEY:
- changeToState(State.START);
- break;
- default:
- changeToState(State.START);
- break;
- }
- }
-
- private void changeToState(State state) {
- switch (state) {
- case START: {
- mCurrentState = State.START;
- mStartFragment = StartFragment.newInstance();
- loadFragment(mStartFragment);
- mBackButton.setText(android.R.string.cancel);
- mNextButton.setText(R.string.btn_next);
- break;
- }
- case CREATE_KEY: {
- mCurrentState = State.CREATE_KEY;
- mCreateKeyFragment = CreateKeyFragment.newInstance();
- loadFragment(mCreateKeyFragment);
- break;
- }
- case IMPORT_KEY: {
- mCurrentState = State.IMPORT_KEY;
- Intent intent = new Intent(this, ImportKeysActivity.class);
- intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN);
- startActivityForResult(intent, REQUEST_CODE_IMPORT);
- break;
- }
- case K9: {
- mCurrentState = State.K9;
- mBackButton.setEnabled(false); // don't go back to import/create key
- mK9Fragment = K9Fragment.newInstance();
- loadFragment(mK9Fragment);
- break;
- }
- }
- }
-
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
index ccc5960c8..e5dbebe01 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
@@ -143,7 +143,7 @@ public class SubkeysAdapter extends CursorAdapter {
// for edit key
if (mSaveKeyringParcel != null) {
- boolean revokeThisSubkey = (mSaveKeyringParcel.revokeSubKeys.contains(keyId));
+ boolean revokeThisSubkey = (mSaveKeyringParcel.mRevokeSubKeys.contains(keyId));
if (revokeThisSubkey) {
if (!isRevoked) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
index 10e299ae3..18312660a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
@@ -131,10 +131,10 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
// for edit key
if (mSaveKeyringParcel != null) {
- boolean changeAnyPrimaryUserId = (mSaveKeyringParcel.changePrimaryUserId != null);
- boolean changeThisPrimaryUserId = (mSaveKeyringParcel.changePrimaryUserId != null
- && mSaveKeyringParcel.changePrimaryUserId.equals(userId));
- boolean revokeThisUserId = (mSaveKeyringParcel.revokeUserIds.contains(userId));
+ boolean changeAnyPrimaryUserId = (mSaveKeyringParcel.mChangePrimaryUserId != null);
+ boolean changeThisPrimaryUserId = (mSaveKeyringParcel.mChangePrimaryUserId != null
+ && mSaveKeyringParcel.mChangePrimaryUserId.equals(userId));
+ boolean revokeThisUserId = (mSaveKeyringParcel.mRevokeUserIds.contains(userId));
// only if primary user id will be changed
// (this is not triggered if the user id is currently the primary one)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
index 4d0b73d30..d723f88af 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
@@ -152,7 +152,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
// above can't be statically verified to have been set in all cases because
// the catch clause doesn't return.
try {
- userId = secretRing.getPrimaryUserId();
+ userId = secretRing.getPrimaryUserIdWithFallback();
} catch (PgpGeneralException e) {
userId = null;
}
@@ -232,7 +232,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
try {
PassphraseCacheService.addCachedPassphrase(activity, masterKeyId, passphrase,
- secretRing.getPrimaryUserId());
+ secretRing.getPrimaryUserIdWithFallback());
} catch(PgpGeneralException e) {
Log.e(Constants.TAG, "adding of a passhrase failed", e);
}
@@ -240,7 +240,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
if (unlockedSecretKey.getKeyId() != masterKeyId) {
PassphraseCacheService.addCachedPassphrase(
activity, unlockedSecretKey.getKeyId(), passphrase,
- unlockedSecretKey.getPrimaryUserId());
+ unlockedSecretKey.getPrimaryUserIdWithFallback());
}
// also return passphrase back to activity
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java
index 5553ea5d2..869eea03f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java
@@ -39,15 +39,21 @@ public class ProgressScaler implements Progressable {
* Set progress of ProgressDialog by sending message to handler on UI thread
*/
public void setProgress(String message, int progress, int max) {
- mWrapped.setProgress(message, mFrom + progress * (mTo - mFrom) / max, mMax);
+ if (mWrapped != null) {
+ mWrapped.setProgress(message, mFrom + progress * (mTo - mFrom) / max, mMax);
+ }
}
public void setProgress(int resourceId, int progress, int max) {
- mWrapped.setProgress(resourceId, progress, mMax);
+ if (mWrapped != null) {
+ mWrapped.setProgress(resourceId, progress, mMax);
+ }
}
public void setProgress(int progress, int max) {
- mWrapped.setProgress(progress, max);
+ if (mWrapped != null) {
+ mWrapped.setProgress(progress, max);
+ }
}
}