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