Merge branch 'master' into yubikey
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
This commit is contained in:
@@ -21,6 +21,8 @@ import android.accounts.Account;
|
||||
import android.app.Service;
|
||||
import android.content.AbstractThreadedSyncAdapter;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SyncResult;
|
||||
import android.os.Bundle;
|
||||
@@ -29,9 +31,11 @@ import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.provider.ContactsContract;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.KeychainApplication;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.ContactHelper;
|
||||
import org.sufficientlysecure.keychain.helper.EmailKeyHelper;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
@@ -42,7 +46,7 @@ public class ContactSyncAdapterService extends Service {
|
||||
|
||||
private class ContactSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
|
||||
private final AtomicBoolean importDone = new AtomicBoolean(false);
|
||||
// private final AtomicBoolean importDone = new AtomicBoolean(false);
|
||||
|
||||
public ContactSyncAdapter() {
|
||||
super(ContactSyncAdapterService.this, true);
|
||||
@@ -51,47 +55,59 @@ public class ContactSyncAdapterService extends Service {
|
||||
@Override
|
||||
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider,
|
||||
final SyncResult syncResult) {
|
||||
importDone.set(false);
|
||||
KeychainApplication.setupAccountAsNeeded(ContactSyncAdapterService.this);
|
||||
EmailKeyHelper.importContacts(getContext(), new Messenger(new Handler(Looper.getMainLooper(),
|
||||
new Handler.Callback() {
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
Bundle data = msg.getData();
|
||||
switch (msg.arg1) {
|
||||
case KeychainIntentServiceHandler.MESSAGE_OKAY:
|
||||
Log.d(Constants.TAG, "Syncing... Done.");
|
||||
synchronized (importDone) {
|
||||
importDone.set(true);
|
||||
importDone.notifyAll();
|
||||
}
|
||||
return true;
|
||||
case KeychainIntentServiceHandler.MESSAGE_UPDATE_PROGRESS:
|
||||
if (data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS) &&
|
||||
data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS_MAX)) {
|
||||
Log.d(Constants.TAG, "Syncing... Progress: " +
|
||||
data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS) + "/" +
|
||||
data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS_MAX));
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
Log.d(Constants.TAG, "Syncing... " + msg.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})));
|
||||
synchronized (importDone) {
|
||||
try {
|
||||
if (!importDone.get()) importDone.wait();
|
||||
} catch (InterruptedException e) {
|
||||
Log.w(Constants.TAG, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Log.d(Constants.TAG, "Performing a sync!");
|
||||
// TODO: Import is currently disabled for 2.8, until we implement proper origin management
|
||||
// importDone.set(false);
|
||||
// KeychainApplication.setupAccountAsNeeded(ContactSyncAdapterService.this);
|
||||
// EmailKeyHelper.importContacts(getContext(), new Messenger(new Handler(Looper.getMainLooper(),
|
||||
// new Handler.Callback() {
|
||||
// @Override
|
||||
// public boolean handleMessage(Message msg) {
|
||||
// Bundle data = msg.getData();
|
||||
// switch (msg.arg1) {
|
||||
// case KeychainIntentServiceHandler.MESSAGE_OKAY:
|
||||
// Log.d(Constants.TAG, "Syncing... Done.");
|
||||
// synchronized (importDone) {
|
||||
// importDone.set(true);
|
||||
// importDone.notifyAll();
|
||||
// }
|
||||
// return true;
|
||||
// case KeychainIntentServiceHandler.MESSAGE_UPDATE_PROGRESS:
|
||||
// if (data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS) &&
|
||||
// data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS_MAX)) {
|
||||
// Log.d(Constants.TAG, "Syncing... Progress: " +
|
||||
// data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS) + "/" +
|
||||
// data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS_MAX));
|
||||
// return false;
|
||||
// }
|
||||
// default:
|
||||
// Log.d(Constants.TAG, "Syncing... " + msg.toString());
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// })));
|
||||
// synchronized (importDone) {
|
||||
// try {
|
||||
// if (!importDone.get()) importDone.wait();
|
||||
// } catch (InterruptedException e) {
|
||||
// Log.w(Constants.TAG, e);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
ContactHelper.writeKeysToContacts(ContactSyncAdapterService.this);
|
||||
}
|
||||
}
|
||||
|
||||
public static void requestSync() {
|
||||
Bundle extras = new Bundle();
|
||||
// no need to wait for internet connection!
|
||||
extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
|
||||
ContentResolver.requestSync(
|
||||
new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE),
|
||||
ContactsContract.AUTHORITY,
|
||||
extras);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return new ContactSyncAdapter().getSyncAdapterBinder();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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
|
||||
@@ -49,11 +50,14 @@ import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.service.OperationResults.ConsolidateResult;
|
||||
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
|
||||
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
|
||||
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
|
||||
import org.sufficientlysecure.keychain.util.FileImportCache;
|
||||
import org.sufficientlysecure.keychain.util.InputData;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
@@ -102,6 +106,10 @@ public class KeychainIntentService extends IntentService
|
||||
|
||||
public static final String ACTION_CERTIFY_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING";
|
||||
|
||||
public static final String ACTION_DELETE = Constants.INTENT_PREFIX + "DELETE";
|
||||
|
||||
public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE";
|
||||
|
||||
/* keys for data bundle */
|
||||
|
||||
// encrypt, decrypt, import export
|
||||
@@ -139,8 +147,13 @@ public class KeychainIntentService extends IntentService
|
||||
// delete file securely
|
||||
public static final String DELETE_FILE = "deleteFile";
|
||||
|
||||
// delete keyring(s)
|
||||
public static final String DELETE_KEY_LIST = "delete_list";
|
||||
public static final String DELETE_IS_SECRET = "delete_is_secret";
|
||||
|
||||
// import key
|
||||
public static final String IMPORT_KEY_LIST = "import_key_list";
|
||||
public static final String IMPORT_KEY_FILE = "import_key_file";
|
||||
|
||||
// export key
|
||||
public static final String EXPORT_OUTPUT_STREAM = "export_output_stream";
|
||||
@@ -162,6 +175,10 @@ public class KeychainIntentService extends IntentService
|
||||
public static final String CERTIFY_KEY_PUB_KEY_ID = "sign_key_pub_key_id";
|
||||
public static final String CERTIFY_KEY_UIDS = "sign_key_uids";
|
||||
|
||||
// consolidate
|
||||
public static final String CONSOLIDATE_RECOVERY = "consolidate_recovery";
|
||||
|
||||
|
||||
/*
|
||||
* possible data keys as result send over messenger
|
||||
*/
|
||||
@@ -176,8 +193,6 @@ public class KeychainIntentService extends IntentService
|
||||
// export
|
||||
public static final String RESULT_EXPORT = "exported";
|
||||
|
||||
public static final String RESULT_IMPORT = "result";
|
||||
|
||||
Messenger mMessenger;
|
||||
|
||||
private boolean mIsCanceled;
|
||||
@@ -246,27 +261,31 @@ public class KeychainIntentService extends IntentService
|
||||
String originalFilename = getOriginalFilename(data);
|
||||
|
||||
/* Operation */
|
||||
PgpSignEncrypt.Builder builder =
|
||||
new PgpSignEncrypt.Builder(
|
||||
new ProviderHelper(this),
|
||||
inputData, outStream);
|
||||
builder.setProgressable(this);
|
||||
|
||||
builder.setEnableAsciiArmorOutput(useAsciiArmor)
|
||||
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
||||
new ProviderHelper(this),
|
||||
inputData, outStream
|
||||
);
|
||||
builder.setProgressable(this)
|
||||
.setEnableAsciiArmorOutput(useAsciiArmor)
|
||||
.setVersionHeader(PgpHelper.getVersionForHeader(this))
|
||||
.setCompressionId(compressionId)
|
||||
.setSymmetricEncryptionAlgorithm(
|
||||
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
|
||||
.setEncryptionMasterKeyIds(encryptionKeyIds)
|
||||
.setSymmetricPassphrase(symmetricPassphrase)
|
||||
.setSignatureMasterKeyId(signatureKeyId)
|
||||
.setEncryptToSigner(true)
|
||||
.setSignatureHashAlgorithm(
|
||||
Preferences.getPreferences(this).getDefaultHashAlgorithm())
|
||||
.setSignaturePassphrase(
|
||||
PassphraseCacheService.getCachedPassphrase(this, signatureKeyId))
|
||||
.setOriginalFilename(originalFilename);
|
||||
|
||||
try {
|
||||
builder.setSignatureMasterKeyId(signatureKeyId)
|
||||
.setSignaturePassphrase(
|
||||
PassphraseCacheService.getCachedPassphrase(this, signatureKeyId))
|
||||
.setSignatureHashAlgorithm(
|
||||
Preferences.getPreferences(this).getDefaultHashAlgorithm())
|
||||
.setAdditionalEncryptId(signatureKeyId);
|
||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||
// encrypt-only
|
||||
}
|
||||
|
||||
// this assumes that the bytes are cleartext (valid for current implementation!)
|
||||
if (source == IO_BYTES) {
|
||||
builder.setCleartextInput(true);
|
||||
@@ -391,23 +410,41 @@ public class KeychainIntentService extends IntentService
|
||||
}
|
||||
|
||||
/* Operation */
|
||||
ProviderHelper providerHelper = new ProviderHelper(this);
|
||||
PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 10, 60, 100));
|
||||
EditKeyResult result;
|
||||
EditKeyResult modifyResult;
|
||||
|
||||
if (saveParcel.mMasterKeyId != null) {
|
||||
String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE);
|
||||
CanonicalizedSecretKeyRing secRing =
|
||||
providerHelper.getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
|
||||
new ProviderHelper(this).getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
|
||||
|
||||
result = keyOperations.modifySecretKeyRing(secRing, saveParcel, passphrase);
|
||||
modifyResult = keyOperations.modifySecretKeyRing(secRing, saveParcel, passphrase);
|
||||
} else {
|
||||
result = keyOperations.createSecretKeyRing(saveParcel);
|
||||
modifyResult = keyOperations.createSecretKeyRing(saveParcel);
|
||||
}
|
||||
|
||||
UncachedKeyRing ring = result.getRing();
|
||||
// If the edit operation didn't succeed, exit here
|
||||
if (!modifyResult.success()) {
|
||||
// always return SaveKeyringResult, so create one out of the EditKeyResult
|
||||
SaveKeyringResult saveResult = new SaveKeyringResult(
|
||||
SaveKeyringResult.RESULT_ERROR,
|
||||
modifyResult.getLog(),
|
||||
null);
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, saveResult);
|
||||
return;
|
||||
}
|
||||
|
||||
providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
|
||||
UncachedKeyRing ring = modifyResult.getRing();
|
||||
|
||||
// Save the keyring. The ProviderHelper is initialized with the previous log
|
||||
SaveKeyringResult saveResult = new ProviderHelper(this, modifyResult.getLog())
|
||||
.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
|
||||
|
||||
// If the edit operation didn't succeed, exit here
|
||||
if (!saveResult.success()) {
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, saveResult);
|
||||
return;
|
||||
}
|
||||
|
||||
// cache new passphrase
|
||||
if (saveParcel.mNewPassphrase != null) {
|
||||
@@ -417,8 +454,11 @@ public class KeychainIntentService extends IntentService
|
||||
|
||||
setProgress(R.string.progress_done, 100, 100);
|
||||
|
||||
// make sure new data is synced into contacts
|
||||
ContactSyncAdapterService.requestSync();
|
||||
|
||||
/* Output */
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, saveResult);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
@@ -454,17 +494,21 @@ public class KeychainIntentService extends IntentService
|
||||
} else {
|
||||
// get entries from cached file
|
||||
FileImportCache<ParcelableKeyRing> cache =
|
||||
new FileImportCache<ParcelableKeyRing>(this);
|
||||
new FileImportCache<ParcelableKeyRing>(this, "key_import.pcl");
|
||||
entries = cache.readCacheIntoList();
|
||||
}
|
||||
|
||||
PgpImportExport pgpImportExport = new PgpImportExport(this, this);
|
||||
ProviderHelper providerHelper = new ProviderHelper(this);
|
||||
PgpImportExport pgpImportExport = new PgpImportExport(this, providerHelper, this);
|
||||
ImportKeyResult result = pgpImportExport.importKeyRings(entries);
|
||||
|
||||
Bundle resultData = new Bundle();
|
||||
resultData.putParcelable(RESULT_IMPORT, result);
|
||||
if (result.mSecret > 0) {
|
||||
providerHelper.consolidateDatabaseStep1(this);
|
||||
}
|
||||
// make sure new data is synced into contacts
|
||||
ContactSyncAdapterService.requestSync();
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
@@ -549,8 +593,9 @@ public class KeychainIntentService extends IntentService
|
||||
CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri);
|
||||
PgpImportExport pgpImportExport = new PgpImportExport(this, null);
|
||||
|
||||
boolean uploaded = pgpImportExport.uploadKeyRingToServer(server, keyring);
|
||||
if (!uploaded) {
|
||||
try {
|
||||
pgpImportExport.uploadKeyRingToServer(server, keyring);
|
||||
} catch (Keyserver.AddKeyException e) {
|
||||
throw new PgpGeneralException("Unable to export key to selected server");
|
||||
}
|
||||
|
||||
@@ -639,7 +684,56 @@ public class KeychainIntentService extends IntentService
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
} else if (ACTION_DELETE.equals(action)) {
|
||||
|
||||
try {
|
||||
|
||||
long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST);
|
||||
boolean isSecret = data.getBoolean(DELETE_IS_SECRET);
|
||||
|
||||
if (masterKeyIds.length == 0) {
|
||||
throw new PgpGeneralException("List of keys to delete is empty");
|
||||
}
|
||||
|
||||
if (isSecret && masterKeyIds.length > 1) {
|
||||
throw new PgpGeneralException("Secret keys can only be deleted individually!");
|
||||
}
|
||||
|
||||
boolean success = false;
|
||||
for (long masterKeyId : masterKeyIds) {
|
||||
int count = getContentResolver().delete(
|
||||
KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null
|
||||
);
|
||||
success |= count > 0;
|
||||
}
|
||||
|
||||
if (isSecret && success) {
|
||||
ConsolidateResult result =
|
||||
new ProviderHelper(this).consolidateDatabaseStep1(this);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
// make sure new data is synced into contacts
|
||||
ContactSyncAdapterService.requestSync();
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
} else if (ACTION_CONSOLIDATE.equals(action)) {
|
||||
ConsolidateResult result;
|
||||
if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) {
|
||||
result = new ProviderHelper(this).consolidateDatabaseStep2(this);
|
||||
} else {
|
||||
result = new ProviderHelper(this).consolidateDatabaseStep1(this);
|
||||
}
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sendErrorToHandler(Exception e) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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
|
||||
@@ -155,10 +156,8 @@ public class OperationResultParcel implements Parcelable {
|
||||
if ((resultType & OperationResultParcel.RESULT_ERROR) == 0) {
|
||||
|
||||
if (getLog().containsWarnings()) {
|
||||
duration = 0;
|
||||
color = Style.ORANGE;
|
||||
} else {
|
||||
duration = SuperToast.Duration.LONG;
|
||||
color = Style.GREEN;
|
||||
}
|
||||
|
||||
@@ -167,7 +166,6 @@ public class OperationResultParcel implements Parcelable {
|
||||
|
||||
} else {
|
||||
|
||||
duration = 0;
|
||||
color = Style.RED;
|
||||
|
||||
str = "operation failed";
|
||||
@@ -180,8 +178,8 @@ public class OperationResultParcel implements Parcelable {
|
||||
button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD,
|
||||
Style.getStyle(color, SuperToast.Animations.POPUP));
|
||||
toast.setText(str);
|
||||
toast.setDuration(duration);
|
||||
toast.setIndeterminate(duration == 0);
|
||||
toast.setDuration(SuperToast.Duration.EXTRA_LONG);
|
||||
toast.setIndeterminate(false);
|
||||
toast.setSwipeToDismiss(true);
|
||||
// If we have a log and it's non-empty, show a View Log button
|
||||
if (button) {
|
||||
@@ -289,6 +287,7 @@ public class OperationResultParcel implements Parcelable {
|
||||
MSG_IS_SUCCESS (R.string.msg_is_success),
|
||||
|
||||
// keyring canonicalization
|
||||
MSG_KC_V3_KEY (R.string.msg_kc_v3_key),
|
||||
MSG_KC_PUBLIC (R.string.msg_kc_public),
|
||||
MSG_KC_SECRET (R.string.msg_kc_secret),
|
||||
MSG_KC_FATAL_NO_UID (R.string.msg_kc_fatal_no_uid),
|
||||
@@ -324,6 +323,7 @@ public class OperationResultParcel implements Parcelable {
|
||||
MSG_KC_UID_BAD_TIME (R.string.msg_kc_uid_bad_time),
|
||||
MSG_KC_UID_BAD_TYPE (R.string.msg_kc_uid_bad_type),
|
||||
MSG_KC_UID_BAD (R.string.msg_kc_uid_bad),
|
||||
MSG_KC_UID_CERT_DUP (R.string.msg_kc_uid_cert_dup),
|
||||
MSG_KC_UID_DUP (R.string.msg_kc_uid_dup),
|
||||
MSG_KC_UID_FOREIGN (R.string.msg_kc_uid_foreign),
|
||||
MSG_KC_UID_NO_CERT (R.string.msg_kc_uid_no_cert),
|
||||
@@ -333,10 +333,11 @@ public class OperationResultParcel implements Parcelable {
|
||||
|
||||
|
||||
// keyring consolidation
|
||||
MSG_MG_ERROR_SECRET_DUMMY(R.string.msg_mg_error_secret_dummy),
|
||||
MSG_MG_ERROR_ENCODE(R.string.msg_mg_error_encode),
|
||||
MSG_MG_ERROR_HETEROGENEOUS(R.string.msg_mg_error_heterogeneous),
|
||||
MSG_MG_PUBLIC (R.string.msg_mg_public),
|
||||
MSG_MG_SECRET (R.string.msg_mg_secret),
|
||||
MSG_MG_FATAL_ENCODE (R.string.msg_mg_fatal_encode),
|
||||
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),
|
||||
@@ -346,10 +347,16 @@ public class OperationResultParcel implements Parcelable {
|
||||
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_NULL_EXPIRY(R.string.msg_cr_error_null_expiry),
|
||||
MSG_CR_ERROR_KEYSIZE_512 (R.string.msg_cr_error_keysize_512),
|
||||
MSG_CR_ERROR_NO_KEYSIZE (R.string.msg_cr_error_no_keysize),
|
||||
MSG_CR_ERROR_NO_CURVE (R.string.msg_cr_error_no_curve),
|
||||
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),
|
||||
MSG_CR_ERROR_FLAGS_DSA (R.string.msg_cr_error_flags_dsa),
|
||||
MSG_CR_ERROR_FLAGS_ELGAMAL (R.string.msg_cr_error_flags_elgamal),
|
||||
MSG_CR_ERROR_FLAGS_ECDSA (R.string.msg_cr_error_flags_ecdsa),
|
||||
MSG_CR_ERROR_FLAGS_ECDH (R.string.msg_cr_error_flags_ecdh),
|
||||
|
||||
// secret key modify
|
||||
MSG_MF (R.string.msg_mr),
|
||||
@@ -357,18 +364,27 @@ 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_MASTER_NONE(R.string.msg_mf_error_master_none),
|
||||
MSG_MF_ERROR_NO_CERTIFY (R.string.msg_cr_error_no_certify),
|
||||
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_NOEXIST_REVOKE (R.string.msg_mf_error_noexist_revoke),
|
||||
MSG_MF_ERROR_NULL_EXPIRY (R.string.msg_mf_error_null_expiry),
|
||||
MSG_MF_ERROR_PASSPHRASE_MASTER(R.string.msg_mf_error_passphrase_master),
|
||||
MSG_MF_ERROR_PAST_EXPIRY(R.string.msg_mf_error_past_expiry),
|
||||
MSG_MF_ERROR_PGP (R.string.msg_mf_error_pgp),
|
||||
MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary),
|
||||
MSG_MF_ERROR_SIG (R.string.msg_mf_error_sig),
|
||||
MSG_MF_ERROR_SUBKEY_MISSING(R.string.msg_mf_error_subkey_missing),
|
||||
MSG_MF_MASTER (R.string.msg_mf_master),
|
||||
MSG_MF_PASSPHRASE (R.string.msg_mf_passphrase),
|
||||
MSG_MF_PASSPHRASE_KEY (R.string.msg_mf_passphrase_key),
|
||||
MSG_MF_PASSPHRASE_EMPTY_RETRY (R.string.msg_mf_passphrase_empty_retry),
|
||||
MSG_MF_PASSPHRASE_FAIL (R.string.msg_mf_passphrase_fail),
|
||||
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),
|
||||
MSG_MF_SUBKEY_NEW (R.string.msg_mf_subkey_new),
|
||||
MSG_MF_SUBKEY_PAST_EXPIRY (R.string.msg_mf_subkey_past_expiry),
|
||||
MSG_MF_SUBKEY_REVOKE (R.string.msg_mf_subkey_revoke),
|
||||
MSG_MF_SUCCESS (R.string.msg_mf_success),
|
||||
MSG_MF_UID_ADD (R.string.msg_mf_uid_add),
|
||||
@@ -377,6 +393,32 @@ public class OperationResultParcel implements Parcelable {
|
||||
MSG_MF_UID_ERROR_EMPTY (R.string.msg_mf_uid_error_empty),
|
||||
MSG_MF_UNLOCK_ERROR (R.string.msg_mf_unlock_error),
|
||||
MSG_MF_UNLOCK (R.string.msg_mf_unlock),
|
||||
|
||||
// consolidate
|
||||
MSG_CON_CRITICAL_IN (R.string.msg_con_critical_in),
|
||||
MSG_CON_CRITICAL_OUT (R.string.msg_con_critical_out),
|
||||
MSG_CON_DB_CLEAR (R.string.msg_con_db_clear),
|
||||
MSG_CON_DELETE_PUBLIC (R.string.msg_con_delete_public),
|
||||
MSG_CON_DELETE_SECRET (R.string.msg_con_delete_secret),
|
||||
MSG_CON_ERROR_BAD_STATE (R.string.msg_con_error_bad_state),
|
||||
MSG_CON_ERROR_CONCURRENT(R.string.msg_con_error_concurrent),
|
||||
MSG_CON_ERROR_DB (R.string.msg_con_error_db),
|
||||
MSG_CON_ERROR_IO_PUBLIC (R.string.msg_con_error_io_public),
|
||||
MSG_CON_ERROR_IO_SECRET (R.string.msg_con_error_io_secret),
|
||||
MSG_CON_ERROR_PUBLIC (R.string.msg_con_error_public),
|
||||
MSG_CON_ERROR_SECRET (R.string.msg_con_error_secret),
|
||||
MSG_CON_RECOVER (R.plurals.msg_con_recover),
|
||||
MSG_CON_RECOVER_UNKNOWN (R.string.msg_con_recover_unknown),
|
||||
MSG_CON_REIMPORT_PUBLIC (R.plurals.msg_con_reimport_public),
|
||||
MSG_CON_REIMPORT_PUBLIC_SKIP (R.string.msg_con_reimport_public_skip),
|
||||
MSG_CON_REIMPORT_SECRET (R.plurals.msg_con_reimport_secret),
|
||||
MSG_CON_REIMPORT_SECRET_SKIP (R.string.msg_con_reimport_secret_skip),
|
||||
MSG_CON (R.string.msg_con),
|
||||
MSG_CON_SAVE_PUBLIC (R.string.msg_con_save_public),
|
||||
MSG_CON_SAVE_SECRET (R.string.msg_con_save_secret),
|
||||
MSG_CON_SUCCESS (R.string.msg_con_success),
|
||||
MSG_CON_WARN_DELETE_PUBLIC (R.string.msg_con_warn_delete_public),
|
||||
MSG_CON_WARN_DELETE_SECRET (R.string.msg_con_warn_delete_secret),
|
||||
;
|
||||
|
||||
private final int mMsgId;
|
||||
@@ -406,7 +448,9 @@ public class OperationResultParcel implements Parcelable {
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mResult);
|
||||
dest.writeTypedList(mLog.toList());
|
||||
if (mLog != null) {
|
||||
dest.writeTypedList(mLog.toList());
|
||||
}
|
||||
}
|
||||
|
||||
public static final Creator<OperationResultParcel> CREATOR = new Creator<OperationResultParcel>() {
|
||||
@@ -432,6 +476,15 @@ public class OperationResultParcel implements Parcelable {
|
||||
mParcels.add(new OperationResultParcel.LogEntryParcel(level, type, indent, (Object[]) null));
|
||||
}
|
||||
|
||||
public boolean containsType(LogType type) {
|
||||
for(LogEntryParcel entry : new IterableIterator<LogEntryParcel>(mParcels.iterator())) {
|
||||
if (entry.mType == type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsWarnings() {
|
||||
for(LogEntryParcel entry : new IterableIterator<LogEntryParcel>(mParcels.iterator())) {
|
||||
if (entry.mLevel == LogLevel.WARN || entry.mLevel == LogLevel.ERROR) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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
|
||||
@@ -28,7 +29,10 @@ import com.github.johnpersano.supertoasts.SuperToast;
|
||||
import com.github.johnpersano.supertoasts.util.OnClickWrapper;
|
||||
import com.github.johnpersano.supertoasts.util.Style;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||
import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
|
||||
import org.sufficientlysecure.keychain.ui.LogDisplayFragment;
|
||||
@@ -37,7 +41,7 @@ public abstract class OperationResults {
|
||||
|
||||
public static class ImportKeyResult extends OperationResultParcel {
|
||||
|
||||
public final int mNewKeys, mUpdatedKeys, mBadKeys;
|
||||
public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret;
|
||||
|
||||
// At least one new key
|
||||
public static final int RESULT_OK_NEWKEYS = 2;
|
||||
@@ -49,18 +53,21 @@ public abstract class OperationResults {
|
||||
public static final int RESULT_WITH_WARNINGS = 16;
|
||||
|
||||
// No keys to import...
|
||||
public static final int RESULT_FAIL_NOTHING = 32 +1;
|
||||
public static final int RESULT_FAIL_NOTHING = 32 + 1;
|
||||
|
||||
public boolean isOkBoth() {
|
||||
return (mResult & (RESULT_OK_NEWKEYS | RESULT_OK_UPDATED))
|
||||
== (RESULT_OK_NEWKEYS | RESULT_OK_UPDATED);
|
||||
}
|
||||
|
||||
public boolean isOkNew() {
|
||||
return (mResult & RESULT_OK_NEWKEYS) == RESULT_OK_NEWKEYS;
|
||||
}
|
||||
|
||||
public boolean isOkUpdated() {
|
||||
return (mResult & RESULT_OK_UPDATED) == RESULT_OK_UPDATED;
|
||||
}
|
||||
|
||||
public boolean isFailNothing() {
|
||||
return (mResult & RESULT_FAIL_NOTHING) == RESULT_FAIL_NOTHING;
|
||||
}
|
||||
@@ -70,14 +77,16 @@ public abstract class OperationResults {
|
||||
mNewKeys = source.readInt();
|
||||
mUpdatedKeys = source.readInt();
|
||||
mBadKeys = source.readInt();
|
||||
mSecret = source.readInt();
|
||||
}
|
||||
|
||||
public ImportKeyResult(int result, OperationLog log,
|
||||
int newKeys, int updatedKeys, int badKeys) {
|
||||
int newKeys, int updatedKeys, int badKeys, int secret) {
|
||||
super(result, log);
|
||||
mNewKeys = newKeys;
|
||||
mUpdatedKeys = updatedKeys;
|
||||
mBadKeys = badKeys;
|
||||
mSecret = secret;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,6 +95,7 @@ public abstract class OperationResults {
|
||||
dest.writeInt(mNewKeys);
|
||||
dest.writeInt(mUpdatedKeys);
|
||||
dest.writeInt(mBadKeys);
|
||||
dest.writeInt(mSecret);
|
||||
}
|
||||
|
||||
public static Creator<ImportKeyResult> CREATOR = new Creator<ImportKeyResult>() {
|
||||
@@ -124,7 +134,7 @@ public abstract class OperationResults {
|
||||
if (this.isOkBoth()) {
|
||||
str = activity.getResources().getQuantityString(
|
||||
R.plurals.import_keys_added_and_updated_1, mNewKeys, mNewKeys);
|
||||
str += " "+ activity.getResources().getQuantityString(
|
||||
str += " " + activity.getResources().getQuantityString(
|
||||
R.plurals.import_keys_added_and_updated_2, mUpdatedKeys, mUpdatedKeys, withWarnings);
|
||||
} else if (isOkUpdated()) {
|
||||
str = activity.getResources().getQuantityString(
|
||||
@@ -185,13 +195,13 @@ public abstract class OperationResults {
|
||||
public static class EditKeyResult extends OperationResultParcel {
|
||||
|
||||
private transient UncachedKeyRing mRing;
|
||||
public final Long mRingMasterKeyId;
|
||||
public final long mRingMasterKeyId;
|
||||
|
||||
public EditKeyResult(int result, OperationLog log,
|
||||
UncachedKeyRing ring) {
|
||||
UncachedKeyRing ring) {
|
||||
super(result, log);
|
||||
mRing = ring;
|
||||
mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : null;
|
||||
mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : Constants.key.none;
|
||||
}
|
||||
|
||||
public UncachedKeyRing getRing() {
|
||||
@@ -224,8 +234,12 @@ public abstract class OperationResults {
|
||||
|
||||
public static class SaveKeyringResult extends OperationResultParcel {
|
||||
|
||||
public SaveKeyringResult(int result, OperationLog log) {
|
||||
public final long mRingMasterKeyId;
|
||||
|
||||
public SaveKeyringResult(int result, OperationLog log,
|
||||
CanonicalizedKeyRing ring) {
|
||||
super(result, log);
|
||||
mRingMasterKeyId = ring != null ? ring.getMasterKeyId() : Constants.key.none;
|
||||
}
|
||||
|
||||
// Some old key was updated
|
||||
@@ -240,6 +254,34 @@ public abstract class OperationResults {
|
||||
return (mResult & UPDATED) == UPDATED;
|
||||
}
|
||||
|
||||
public SaveKeyringResult(Parcel source) {
|
||||
super(source);
|
||||
mRingMasterKeyId = source.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeLong(mRingMasterKeyId);
|
||||
}
|
||||
|
||||
public static Creator<SaveKeyringResult> CREATOR = new Creator<SaveKeyringResult>() {
|
||||
public SaveKeyringResult createFromParcel(final Parcel source) {
|
||||
return new SaveKeyringResult(source);
|
||||
}
|
||||
|
||||
public SaveKeyringResult[] newArray(final int size) {
|
||||
return new SaveKeyringResult[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class ConsolidateResult extends OperationResultParcel {
|
||||
|
||||
public ConsolidateResult(int result, OperationLog log) {
|
||||
super(result, log);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class PassphraseCacheService extends Service {
|
||||
private static final int NOTIFICATION_ID = 1;
|
||||
|
||||
private static final int MSG_PASSPHRASE_CACHE_GET_OKAY = 1;
|
||||
private static final int MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND = 2;
|
||||
private static final int MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND = 2;
|
||||
|
||||
private BroadcastReceiver mIntentReceiver;
|
||||
|
||||
@@ -170,7 +170,7 @@ public class PassphraseCacheService extends Service {
|
||||
switch (returnMessage.what) {
|
||||
case MSG_PASSPHRASE_CACHE_GET_OKAY:
|
||||
return returnMessage.getData().getString(EXTRA_PASSPHRASE);
|
||||
case MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND:
|
||||
case MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND:
|
||||
throw new KeyNotFoundException();
|
||||
default:
|
||||
throw new KeyNotFoundException("should not happen!");
|
||||
@@ -322,7 +322,7 @@ public class PassphraseCacheService extends Service {
|
||||
msg.setData(bundle);
|
||||
} catch (ProviderHelper.NotFoundException e) {
|
||||
Log.e(Constants.TAG, "PassphraseCacheService: Passphrase for unknown key was requested!");
|
||||
msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NO_FOUND;
|
||||
msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||
*
|
||||
* 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
|
||||
@@ -79,14 +80,16 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
// performance gain for using Parcelable here would probably be negligible,
|
||||
// use Serializable instead.
|
||||
public static class SubkeyAdd implements Serializable {
|
||||
public int mAlgorithm;
|
||||
public int mKeysize;
|
||||
public Algorithm mAlgorithm;
|
||||
public Integer mKeySize;
|
||||
public Curve mCurve;
|
||||
public int mFlags;
|
||||
public Long mExpiry;
|
||||
|
||||
public SubkeyAdd(int algorithm, int keysize, int flags, Long expiry) {
|
||||
public SubkeyAdd(Algorithm algorithm, Integer keySize, Curve curve, int flags, Long expiry) {
|
||||
mAlgorithm = algorithm;
|
||||
mKeysize = keysize;
|
||||
mKeySize = keySize;
|
||||
mCurve = curve;
|
||||
mFlags = flags;
|
||||
mExpiry = expiry;
|
||||
}
|
||||
@@ -94,7 +97,8 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
@Override
|
||||
public String toString() {
|
||||
String out = "mAlgorithm: " + mAlgorithm + ", ";
|
||||
out += "mKeysize: " + mKeysize + ", ";
|
||||
out += "mKeySize: " + mKeySize + ", ";
|
||||
out += "mCurve: " + mCurve + ", ";
|
||||
out += "mFlags: " + mFlags;
|
||||
out += "mExpiry: " + mExpiry;
|
||||
|
||||
@@ -213,4 +217,20 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// All supported algorithms
|
||||
public enum Algorithm {
|
||||
RSA, DSA, ELGAMAL, ECDSA, ECDH
|
||||
}
|
||||
|
||||
// All curves defined in the standard
|
||||
// http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269
|
||||
public enum Curve {
|
||||
NIST_P256, NIST_P384, NIST_P521,
|
||||
|
||||
// these are supported by gpg, but they are not in rfc6637 and not supported by BouncyCastle yet
|
||||
// (adding support would be trivial though -> JcaPGPKeyConverter.java:190)
|
||||
// BRAINPOOL_P256, BRAINPOOL_P384, BRAINPOOL_P512
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user