ImportKeys: Get reference to canonicalized key without saving and refactoring (WIP)

This commit is contained in:
Andrea Torlaschi
2016-07-22 23:57:46 +02:00
parent 68b015122b
commit 15b7845b16
12 changed files with 287 additions and 198 deletions

View File

@@ -1,16 +1,9 @@
package org.sufficientlysecure.keychain.keyimport.processing; package org.sufficientlysecure.keychain.keyimport.processing;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; public interface ImportKeysListener extends ImportKeysResultListener {
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
public interface ImportKeysListener {
void loadKeys(LoaderState loaderState); void loadKeys(LoaderState loaderState);
void importKey(ParcelableKeyRing keyRing);
void importKeys(); void importKeys();
void handleResult(ImportKeyResult result);
} }

View File

@@ -1,32 +1,26 @@
package org.sufficientlysecure.keychain.keyimport.processing; package org.sufficientlysecure.keychain.keyimport.processing;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import java.util.ArrayList;
public class ImportKeysOperationCallback implements public class ImportKeysOperationCallback implements
CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> { CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> {
private ImportKeysListener mResultListener; private ImportKeysResultListener mResultListener;
private String mKeyserver; private ImportKeyringParcel mKeyringParcel;
private ArrayList<ParcelableKeyRing> mKeyList;
public ImportKeysOperationCallback( public ImportKeysOperationCallback(
ImportKeysListener resultListener, ImportKeysResultListener resultListener,
String keyserver, ImportKeyringParcel inputParcel
ArrayList<ParcelableKeyRing> keyList
) { ) {
this.mResultListener = resultListener; this.mResultListener = resultListener;
this.mKeyserver = keyserver; this.mKeyringParcel = inputParcel;
this.mKeyList = keyList;
} }
@Override @Override
public ImportKeyringParcel createOperationInput() { public ImportKeyringParcel createOperationInput() {
return new ImportKeyringParcel(mKeyList, mKeyserver); return mKeyringParcel;
} }
@Override @Override

View File

@@ -0,0 +1,10 @@
package org.sufficientlysecure.keychain.keyimport.processing;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
public interface ImportKeysResultListener {
void handleResult(ImportKeyResult result);
}

View File

@@ -35,6 +35,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
@@ -78,8 +79,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
* not include self certificates for user ids in the secret keyring. The import * not include self certificates for user ids in the secret keyring. The import
* method here will generally import keyrings in the order given by the * method here will generally import keyrings in the order given by the
* iterator, so this should be ensured beforehand. * iterator, so this should be ensured beforehand.
*
* @see org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter#getSelectedEntries()
*/ */
public class ImportOperation extends BaseOperation<ImportKeyringParcel> { public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
@@ -99,20 +98,20 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
// Overloaded functions for using progressable supplied in constructor during import // Overloaded functions for using progressable supplied in constructor during import
public ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num, public ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num,
String keyServerUri, Proxy proxy) { String keyServerUri, Proxy proxy, boolean skipSave) {
return serialKeyRingImport(entries, num, keyServerUri, mProgressable, proxy); return serialKeyRingImport(entries, num, keyServerUri, mProgressable, proxy, skipSave);
} }
@NonNull @NonNull
private ImportKeyResult serialKeyRingImport(ParcelableFileCache<ParcelableKeyRing> cache, private ImportKeyResult serialKeyRingImport(ParcelableFileCache<ParcelableKeyRing> cache,
String keyServerUri, Proxy proxy) { String keyServerUri, Proxy proxy, boolean skipSave) {
// get entries from cached file // get entries from cached file
try { try {
IteratorWithSize<ParcelableKeyRing> it = cache.readCache(); IteratorWithSize<ParcelableKeyRing> it = cache.readCache();
int numEntries = it.getSize(); int numEntries = it.getSize();
return serialKeyRingImport(it, numEntries, keyServerUri, mProgressable, proxy); return serialKeyRingImport(it, numEntries, keyServerUri, mProgressable, proxy, skipSave);
} catch (IOException e) { } catch (IOException e) {
// Special treatment here, we need a lot // Special treatment here, we need a lot
@@ -138,7 +137,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
@NonNull @NonNull
private ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num, private ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num,
String keyServerUri, Progressable progressable, String keyServerUri, Progressable progressable,
@NonNull Proxy proxy) { @NonNull Proxy proxy, boolean skipSave) {
if (progressable != null) { if (progressable != null) {
progressable.setProgress(R.string.progress_importing, 0, 100); progressable.setProgress(R.string.progress_importing, 0, 100);
} }
@@ -154,6 +153,8 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
int newKeys = 0, updatedKeys = 0, badKeys = 0, secret = 0; int newKeys = 0, updatedKeys = 0, badKeys = 0, secret = 0;
ArrayList<Long> importedMasterKeyIds = new ArrayList<>(); ArrayList<Long> importedMasterKeyIds = new ArrayList<>();
ArrayList<CanonicalizedKeyRing> canKeyRings = new ArrayList<>();
boolean cancelled = false; boolean cancelled = false;
int position = 0; int position = 0;
double progSteps = 100.0 / num; double progSteps = 100.0 / num;
@@ -315,14 +316,14 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
// and https://github.com/open-keychain/open-keychain/issues/1480 // and https://github.com/open-keychain/open-keychain/issues/1480
synchronized (mProviderHelper) { synchronized (mProviderHelper) {
mProviderHelper.clearLog(); mProviderHelper.clearLog();
ProgressScaler progressScaler = new ProgressScaler(progressable, (int) (position * progSteps),
(int) ((position + 1) * progSteps), 100);
if (key.isSecret()) { if (key.isSecret()) {
result = mProviderHelper.saveSecretKeyRing(key, result = mProviderHelper.saveSecretKeyRing(key, progressScaler,
new ProgressScaler(progressable, (int) (position * progSteps), canKeyRings, skipSave);
(int) ((position + 1) * progSteps), 100));
} else { } else {
result = mProviderHelper.savePublicKeyRing(key, result = mProviderHelper.savePublicKeyRing(key, progressScaler,
new ProgressScaler(progressable, (int) (position * progSteps), entry.mExpectedFingerprint, canKeyRings, skipSave);
(int) ((position + 1) * progSteps), 100), entry.mExpectedFingerprint);
} }
} }
if (!result.success()) { if (!result.success()) {
@@ -361,7 +362,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
// synchronized on mProviderHelper to prevent // synchronized on mProviderHelper to prevent
// https://github.com/open-keychain/open-keychain/issues/1221 since a consolidate deletes // https://github.com/open-keychain/open-keychain/issues/1221 since a consolidate deletes
// and re-inserts keys, which could conflict with a parallel db key update // and re-inserts keys, which could conflict with a parallel db key update
if (secret > 0) { if (!skipSave && secret > 0) {
setPreventCancel(); setPreventCancel();
ConsolidateResult result; ConsolidateResult result;
synchronized (mProviderHelper) { synchronized (mProviderHelper) {
@@ -419,8 +420,11 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
} }
} }
return new ImportKeyResult(resultType, log, newKeys, updatedKeys, badKeys, secret, ImportKeyResult result = new ImportKeyResult(resultType, log, newKeys, updatedKeys, badKeys, secret,
importedMasterKeyIdsArray); importedMasterKeyIdsArray);
result.setCanonicalizedKeyRings(canKeyRings);
return result;
} }
@NonNull @NonNull
@@ -428,13 +432,13 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
public ImportKeyResult execute(ImportKeyringParcel importInput, CryptoInputParcel cryptoInput) { public ImportKeyResult execute(ImportKeyringParcel importInput, CryptoInputParcel cryptoInput) {
ArrayList<ParcelableKeyRing> keyList = importInput.mKeyList; ArrayList<ParcelableKeyRing> keyList = importInput.mKeyList;
String keyServer = importInput.mKeyserver; String keyServer = importInput.mKeyserver;
boolean skipSave = importInput.mSkipSave;
ImportKeyResult result; ImportKeyResult result;
if (keyList == null) {// import from file, do serially if (keyList == null) {// import from file, do serially
ParcelableFileCache<ParcelableKeyRing> cache = ParcelableFileCache<ParcelableKeyRing> cache =
new ParcelableFileCache<>(mContext, CACHE_FILE_NAME); new ParcelableFileCache<>(mContext, CACHE_FILE_NAME);
result = serialKeyRingImport(cache, null, null); result = serialKeyRingImport(cache, null, null, skipSave);
} else { } else {
Proxy proxy; Proxy proxy;
if (cryptoInput.getParcelableProxy() == null) { if (cryptoInput.getParcelableProxy() == null) {
@@ -449,7 +453,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
proxy = cryptoInput.getParcelableProxy().getProxy(); proxy = cryptoInput.getParcelableProxy().getProxy();
} }
result = multiThreadedKeyImport(keyList.iterator(), keyList.size(), keyServer, proxy); result = multiThreadedKeyImport(keyList, keyServer, proxy, skipSave);
} }
ContactSyncAdapterService.requestContactsSync(); ContactSyncAdapterService.requestContactsSync();
@@ -457,44 +461,43 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
} }
@NonNull @NonNull
private ImportKeyResult multiThreadedKeyImport(@NonNull Iterator<ParcelableKeyRing> keyListIterator, private ImportKeyResult multiThreadedKeyImport(ArrayList<ParcelableKeyRing> keyList,
int totKeys, final String keyServer, final String keyServer, final Proxy proxy,
final Proxy proxy) { final boolean skipSave) {
Log.d(Constants.TAG, "Multi-threaded key import starting");
KeyImportAccumulator accumulator = new KeyImportAccumulator(totKeys, mProgressable);
final ProgressScaler ignoreProgressable = new ProgressScaler(); Log.d(Constants.TAG, "Multi-threaded key import starting");
final Iterator<ParcelableKeyRing> keyListIterator = keyList.iterator();
final int totKeys = keyList.size();
ExecutorService importExecutor = new ThreadPoolExecutor(0, MAX_THREADS, 30L, TimeUnit.SECONDS, ExecutorService importExecutor = new ThreadPoolExecutor(0, MAX_THREADS, 30L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>()); new LinkedBlockingQueue<Runnable>());
ExecutorCompletionService<ImportKeyResult> importCompletionService = ExecutorCompletionService<ImportKeyResult> importCompletionService =
new ExecutorCompletionService<>(importExecutor); new ExecutorCompletionService<>(importExecutor);
while (keyListIterator.hasNext()) { // submit all key rings to be imported while (keyListIterator.hasNext()) { // submit all key rings to be imported
final ParcelableKeyRing pkRing = keyListIterator.next();
Callable<ImportKeyResult> importOperationCallable = new Callable<ImportKeyResult> Callable<ImportKeyResult> importOperationCallable = new Callable<ImportKeyResult>
() { () {
@Override @Override
public ImportKeyResult call() { public ImportKeyResult call() {
if (checkCancelled()) { if (checkCancelled()) {
return null; return null;
} }
ArrayList<ParcelableKeyRing> list = new ArrayList<>(); ArrayList<ParcelableKeyRing> list = new ArrayList<>();
list.add(pkRing); list.add(keyListIterator.next());
ProgressScaler ignoreProgressable = new ProgressScaler();
return serialKeyRingImport(list.iterator(), 1, keyServer, ignoreProgressable, proxy); return serialKeyRingImport(list.iterator(), 1, keyServer, ignoreProgressable,
proxy, skipSave);
} }
}; };
importCompletionService.submit(importOperationCallable); importCompletionService.submit(importOperationCallable);
} }
KeyImportAccumulator accumulator = new KeyImportAccumulator(totKeys, mProgressable);
while (!accumulator.isImportFinished()) { // accumulate the results of each import while (!accumulator.isImportFinished()) { // accumulate the results of each import
try { try {
accumulator.accumulateKeyImport(importCompletionService.take().get()); accumulator.accumulateKeyImport(importCompletionService.take().get());
@@ -511,7 +514,6 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
} }
} }
return accumulator.getConsolidatedResult(); return accumulator.getConsolidatedResult();
} }
/** /**
@@ -519,10 +521,10 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
*/ */
public static class KeyImportAccumulator { public static class KeyImportAccumulator {
private OperationResult.OperationLog mImportLog = new OperationResult.OperationLog(); private OperationResult.OperationLog mImportLog = new OperationResult.OperationLog();
Progressable mProgressable; private Progressable mProgressable;
private int mTotalKeys; private int mTotalKeys;
private int mImportedKeys = 0; private int mImportedKeys = 0;
ArrayList<Long> mImportedMasterKeyIds = new ArrayList<>(); private ArrayList<Long> mImportedMasterKeyIds = new ArrayList<>();
private int mBadKeys = 0; private int mBadKeys = 0;
private int mNewKeys = 0; private int mNewKeys = 0;
private int mUpdatedKeys = 0; private int mUpdatedKeys = 0;
@@ -530,6 +532,8 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
private int mResultType = 0; private int mResultType = 0;
private boolean mHasCancelledResult; private boolean mHasCancelledResult;
public ArrayList<CanonicalizedKeyRing> mCanonicalizedKeyRings;
/** /**
* Accumulates keyring imports and updates the progressable whenever a new key is imported. * Accumulates keyring imports and updates the progressable whenever a new key is imported.
* Also sets the progress to 0 on instantiation. * Also sets the progress to 0 on instantiation.
@@ -544,6 +548,8 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
if (mProgressable != null) { if (mProgressable != null) {
mProgressable.setProgress(0, totalKeys); mProgressable.setProgress(0, totalKeys);
} }
mCanonicalizedKeyRings = new ArrayList<>();
} }
public void accumulateKeyImport(ImportKeyResult result) { public void accumulateKeyImport(ImportKeyResult result) {
@@ -575,6 +581,8 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
mImportedMasterKeyIds.add(masterKeyId); mImportedMasterKeyIds.add(masterKeyId);
} }
mCanonicalizedKeyRings.addAll(result.mCanonicalizedKeyRings);
// if any key import has been cancelled, set result type to cancelled // if any key import has been cancelled, set result type to cancelled
// resultType is added to in getConsolidatedKayImport to account for remaining factors // resultType is added to in getConsolidatedKayImport to account for remaining factors
mResultType |= result.getResult() & ImportKeyResult.RESULT_CANCELLED; mResultType |= result.getResult() & ImportKeyResult.RESULT_CANCELLED;
@@ -614,8 +622,11 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
masterKeyIds[i] = mImportedMasterKeyIds.get(i); masterKeyIds[i] = mImportedMasterKeyIds.get(i);
} }
return new ImportKeyResult(mResultType, mImportLog, mNewKeys, mUpdatedKeys, mBadKeys, ImportKeyResult result = new ImportKeyResult(mResultType, mImportLog, mNewKeys,
mSecret, masterKeyIds); mUpdatedKeys, mBadKeys, mSecret, masterKeyIds);
result.setCanonicalizedKeyRings(mCanonicalizedKeyRings);
return result;
} }
public boolean isImportFinished() { public boolean isImportFinished() {

View File

@@ -23,6 +23,7 @@ import android.content.Intent;
import android.os.Parcel; import android.os.Parcel;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.LogDisplayActivity; import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
@@ -32,11 +33,16 @@ import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
import org.sufficientlysecure.keychain.ui.util.Notify.Showable; import org.sufficientlysecure.keychain.ui.util.Notify.Showable;
import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import java.util.ArrayList;
public class ImportKeyResult extends InputPendingResult { public class ImportKeyResult extends InputPendingResult {
public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret; public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret;
public final long[] mImportedMasterKeyIds; public final long[] mImportedMasterKeyIds;
// NOT PARCELED
public ArrayList<CanonicalizedKeyRing> mCanonicalizedKeyRings;
// At least one new key // At least one new key
public static final int RESULT_OK_NEWKEYS = 8; public static final int RESULT_OK_NEWKEYS = 8;
// At least one updated key // At least one updated key
@@ -107,6 +113,10 @@ public class ImportKeyResult extends InputPendingResult {
mImportedMasterKeyIds = new long[]{}; mImportedMasterKeyIds = new long[]{};
} }
public void setCanonicalizedKeyRings(ArrayList<CanonicalizedKeyRing> canonicalizedKeyRings) {
this.mCanonicalizedKeyRings = canonicalizedKeyRings;
}
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags); super.writeToParcel(dest, flags);
@@ -128,7 +138,6 @@ public class ImportKeyResult extends InputPendingResult {
}; };
public Showable createNotify(final Activity activity) { public Showable createNotify(final Activity activity) {
int resultType = getResult(); int resultType = getResult();
String str; String str;
@@ -204,7 +213,6 @@ public class ImportKeyResult extends InputPendingResult {
activity.startActivity(intent); activity.startActivity(intent);
} }
}, R.string.snackbar_details); }, R.string.snackbar_details);
} }
} }

View File

@@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
@@ -904,7 +905,7 @@ public class ProviderHelper {
} }
public SaveKeyringResult savePublicKeyRing(UncachedKeyRing keyRing) { public SaveKeyringResult savePublicKeyRing(UncachedKeyRing keyRing) {
return savePublicKeyRing(keyRing, new ProgressScaler(), null); return savePublicKeyRing(keyRing, new ProgressScaler(), null, null, false);
} }
/** /**
@@ -913,7 +914,10 @@ public class ProviderHelper {
* This is a high level method, which takes care of merging all new information into the old and * This is a high level method, which takes care of merging all new information into the old and
* keep public and secret keyrings in sync. * keep public and secret keyrings in sync.
*/ */
public SaveKeyringResult savePublicKeyRing(UncachedKeyRing publicRing, Progressable progress, String expectedFingerprint) { public SaveKeyringResult savePublicKeyRing(UncachedKeyRing publicRing, Progressable progress,
String expectedFingerprint,
ArrayList<CanonicalizedKeyRing> canKeyRings,
boolean skipSave) {
try { try {
long masterKeyId = publicRing.getMasterKeyId(); long masterKeyId = publicRing.getMasterKeyId();
@@ -997,12 +1001,21 @@ public class ProviderHelper {
} }
} }
int result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, canSecretRing != null); int result = SaveKeyringResult.SAVED_PUBLIC;
if (!skipSave) {
result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, canSecretRing != null);
}
if (canKeyRings != null) canKeyRings.add(canPublicRing);
// Save the saved keyring (if any) // Save the saved keyring (if any)
if (canSecretRing != null) { if (canSecretRing != null) {
progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100); progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100);
int secretResult = saveCanonicalizedSecretKeyRing(canSecretRing);
int secretResult = SaveKeyringResult.SAVED_SECRET;
if (!skipSave) {
saveCanonicalizedSecretKeyRing(canSecretRing);
}
if ((secretResult & SaveKeyringResult.RESULT_ERROR) != SaveKeyringResult.RESULT_ERROR) { if ((secretResult & SaveKeyringResult.RESULT_ERROR) != SaveKeyringResult.RESULT_ERROR) {
result |= SaveKeyringResult.SAVED_SECRET; result |= SaveKeyringResult.SAVED_SECRET;
} }
@@ -1020,6 +1033,12 @@ public class ProviderHelper {
} }
public SaveKeyringResult saveSecretKeyRing(UncachedKeyRing secretRing, Progressable progress) { public SaveKeyringResult saveSecretKeyRing(UncachedKeyRing secretRing, Progressable progress) {
return saveSecretKeyRing(secretRing, progress, null, false);
}
public SaveKeyringResult saveSecretKeyRing(UncachedKeyRing secretRing, Progressable progress,
ArrayList<CanonicalizedKeyRing> canKeyRings,
boolean skipSave) {
try { try {
long masterKeyId = secretRing.getMasterKeyId(); long masterKeyId = secretRing.getMasterKeyId();
@@ -1109,15 +1128,22 @@ public class ProviderHelper {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
} }
int result; int publicResult = SaveKeyringResult.SAVED_PUBLIC;
if (!skipSave) {
publicResult = saveCanonicalizedPublicKeyRing(canPublicRing, progress, true);
}
result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, true); if ((publicResult & SaveKeyringResult.RESULT_ERROR) == SaveKeyringResult.RESULT_ERROR) {
if ((result & SaveKeyringResult.RESULT_ERROR) == SaveKeyringResult.RESULT_ERROR) {
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
} }
progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100); progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100);
result = saveCanonicalizedSecretKeyRing(canSecretRing);
int result = SaveKeyringResult.SAVED_SECRET;
if (!skipSave) {
result = saveCanonicalizedSecretKeyRing(canSecretRing);
}
if (canKeyRings != null) canKeyRings.add(canSecretRing);
return new SaveKeyringResult(result, mLog, canSecretRing); return new SaveKeyringResult(result, mLog, canSecretRing);
@@ -1350,7 +1376,7 @@ public class ProviderHelper {
ImportKeyResult result = new ImportOperation(mContext, this, ImportKeyResult result = new ImportOperation(mContext, this,
new ProgressFixedScaler(progress, 10, 25, 100, R.string.progress_con_reimport)) new ProgressFixedScaler(progress, 10, 25, 100, R.string.progress_con_reimport))
.serialKeyRingImport(itSecrets, numSecrets, null, null); .serialKeyRingImport(itSecrets, numSecrets, null, null, false);
log.add(result, indent); log.add(result, indent);
} else { } else {
log.add(LogType.MSG_CON_REIMPORT_SECRET_SKIP, indent); log.add(LogType.MSG_CON_REIMPORT_SECRET_SKIP, indent);
@@ -1378,7 +1404,7 @@ public class ProviderHelper {
ImportKeyResult result = new ImportOperation(mContext, this, ImportKeyResult result = new ImportOperation(mContext, this,
new ProgressFixedScaler(progress, 25, 99, 100, R.string.progress_con_reimport)) new ProgressFixedScaler(progress, 25, 99, 100, R.string.progress_con_reimport))
.serialKeyRingImport(itPublics, numPublics, null, null); .serialKeyRingImport(itPublics, numPublics, null, null, false);
log.add(result, indent); log.add(result, indent);
// re-insert our backed up list of updated key times // re-insert our backed up list of updated key times
// TODO: can this cause issues in case a public key re-import failed? // TODO: can this cause issues in case a public key re-import failed?

View File

@@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.service;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import java.util.ArrayList; import java.util.ArrayList;
@@ -28,12 +29,18 @@ public class ImportKeyringParcel implements Parcelable {
// if null, keys are expected to be read from a cache file in ImportExportOperations // if null, keys are expected to be read from a cache file in ImportExportOperations
public ArrayList<ParcelableKeyRing> mKeyList; public ArrayList<ParcelableKeyRing> mKeyList;
public String mKeyserver; // must be set if keys are to be imported from a keyserver public String mKeyserver; // must be set if keys are to be imported from a keyserver
public boolean mSkipSave = false; // don't save the key, only return it as part of result
public ImportKeyringParcel (ArrayList<ParcelableKeyRing> keyList, String keyserver) { public ImportKeyringParcel(ArrayList<ParcelableKeyRing> keyList, String keyserver) {
mKeyList = keyList; mKeyList = keyList;
mKeyserver = keyserver; mKeyserver = keyserver;
} }
public ImportKeyringParcel(ArrayList<ParcelableKeyRing> keyList, String keyserver, boolean skipSave) {
this(keyList, keyserver);
mSkipSave = skipSave;
}
protected ImportKeyringParcel(Parcel in) { protected ImportKeyringParcel(Parcel in) {
if (in.readByte() == 0x01) { if (in.readByte() == 0x01) {
mKeyList = new ArrayList<>(); mKeyList = new ArrayList<>();
@@ -42,6 +49,7 @@ public class ImportKeyringParcel implements Parcelable {
mKeyList = null; mKeyList = null;
} }
mKeyserver = in.readString(); mKeyserver = in.readString();
mSkipSave = in.readInt() != 0;
} }
@Override @Override
@@ -58,6 +66,7 @@ public class ImportKeyringParcel implements Parcelable {
dest.writeList(mKeyList); dest.writeList(mKeyList);
} }
dest.writeString(mKeyserver); dest.writeString(mKeyserver);
dest.writeInt(mSkipSave ? 1 : 0);
} }
public static final Parcelable.Creator<ImportKeyringParcel> CREATOR = new Parcelable.Creator<ImportKeyringParcel>() { public static final Parcelable.Creator<ImportKeyringParcel> CREATOR = new Parcelable.Creator<ImportKeyringParcel>() {

View File

@@ -32,8 +32,6 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.intents.OpenKeychainIntents; import org.sufficientlysecure.keychain.intents.OpenKeychainIntents;
import org.sufficientlysecure.keychain.keyimport.FacebookKeyserver; import org.sufficientlysecure.keychain.keyimport.FacebookKeyserver;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.keyimport.processing.BytesLoaderState;
import org.sufficientlysecure.keychain.keyimport.processing.CloudLoaderState;
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysListener; import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysListener;
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysOperationCallback; import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysOperationCallback;
import org.sufficientlysecure.keychain.keyimport.processing.LoaderState; import org.sufficientlysecure.keychain.keyimport.processing.LoaderState;
@@ -49,7 +47,6 @@ import org.sufficientlysecure.keychain.util.ParcelableFileCache;
import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Preferences;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
public class ImportKeysActivity extends BaseActivity implements ImportKeysListener { public class ImportKeysActivity extends BaseActivity implements ImportKeysListener {
@@ -333,55 +330,11 @@ public class ImportKeysActivity extends BaseActivity implements ImportKeysListen
listFragment.loadState(loaderState); listFragment.loadState(loaderState);
} }
@Override
public void importKey(ParcelableKeyRing keyRing) {
FragmentManager fM = getSupportFragmentManager();
ImportKeysListFragment listFragment = (ImportKeysListFragment) fM.findFragmentByTag(TAG_FRAG_LIST);
String keyserver = null;
ArrayList<ParcelableKeyRing> keyList = null;
Log.d(Constants.TAG, "importKey started");
LoaderState loaderState = listFragment.getState();
if (loaderState instanceof BytesLoaderState) {
// instead of giving the entries by Intent extra, cache them into a
// file to prevent Java Binder problems on heavy imports
// read FileImportCache for more info.
try {
// We parcel this iteratively into a file - anything we can
// display here, we should be able to import.
ParcelableFileCache<ParcelableKeyRing> cache =
new ParcelableFileCache<>(this, ImportOperation.CACHE_FILE_NAME);
cache.writeCache(keyRing);
} catch (IOException e) {
Log.e(Constants.TAG, "Problem writing cache file", e);
Notify.create(this, "Problem writing cache file!", Notify.Style.ERROR).show();
return;
}
} else if (loaderState instanceof CloudLoaderState) {
ArrayList<ParcelableKeyRing> keys = new ArrayList<>();
keys.add(keyRing);
keyList = keys;
keyserver = ((CloudLoaderState) loaderState).mCloudPrefs.keyserver;
}
ImportKeysOperationCallback cb = new ImportKeysOperationCallback(this, keyserver, keyList);
mOperationHelper = new CryptoOperationHelper(1, this, cb, R.string.progress_importing);
mOperationHelper.cryptoOperation();
}
@Override @Override
public void importKeys() { public void importKeys() {
FragmentManager fM = getSupportFragmentManager(); FragmentManager fM = getSupportFragmentManager();
ImportKeysListFragment listFragment = (ImportKeysListFragment) fM.findFragmentByTag(TAG_FRAG_LIST); ImportKeysListFragment listFragment = (ImportKeysListFragment) fM.findFragmentByTag(TAG_FRAG_LIST);
if (listFragment.getEntries().size() == 0) {
Notify.create(this, R.string.error_nothing_import_selected, Notify.Style.ERROR).show();
return;
}
Log.d(Constants.TAG, "importKeys started"); Log.d(Constants.TAG, "importKeys started");
// instead of giving the entries by Intent extra, cache them into a // instead of giving the entries by Intent extra, cache them into a
// file to prevent Java Binder problems on heavy imports // file to prevent Java Binder problems on heavy imports
@@ -398,8 +351,10 @@ public class ImportKeysActivity extends BaseActivity implements ImportKeysListen
return; return;
} }
ImportKeysOperationCallback callback = new ImportKeysOperationCallback(this, null, null); ImportKeyringParcel inputParcel = new ImportKeyringParcel(null, null);
new CryptoOperationHelper(1, this, callback, R.string.progress_importing).cryptoOperation(); ImportKeysOperationCallback callback = new ImportKeysOperationCallback(this, inputParcel);
mOperationHelper = new CryptoOperationHelper(1, this, callback, R.string.progress_importing);
mOperationHelper.cryptoOperation();
} }
@Override @Override

View File

@@ -126,7 +126,7 @@ public class ImportKeysListFragment extends Fragment implements
}; };
} }
public List<ImportKeysListEntry> getEntries() { private List<ImportKeysListEntry> getEntries() {
if (mAdapter != null) { if (mAdapter != null) {
return mAdapter.getEntries(); return mAdapter.getEntries();
} else { } else {

View File

@@ -17,10 +17,10 @@
package org.sufficientlysecure.keychain.ui.adapter; package org.sufficientlysecure.keychain.ui.adapter;
import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.databinding.DataBindingUtil; import android.databinding.DataBindingUtil;
import android.graphics.Color; import android.graphics.Color;
import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -28,6 +28,7 @@ import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.openintents.openpgp.util.OpenPgpUtils; import org.openintents.openpgp.util.OpenPgpUtils;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.databinding.ImportKeysListItemBinding; import org.sufficientlysecure.keychain.databinding.ImportKeysListItemBinding;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
@@ -35,14 +36,24 @@ import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.keyimport.processing.BytesLoaderState; import org.sufficientlysecure.keychain.keyimport.processing.BytesLoaderState;
import org.sufficientlysecure.keychain.keyimport.processing.CloudLoaderState; import org.sufficientlysecure.keychain.keyimport.processing.CloudLoaderState;
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysListener; import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysListener;
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysOperationCallback;
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysResultListener;
import org.sufficientlysecure.keychain.keyimport.processing.LoaderState; import org.sufficientlysecure.keychain.keyimport.processing.LoaderState;
import org.sufficientlysecure.keychain.operations.ImportOperation; import org.sufficientlysecure.keychain.operations.ImportOperation;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Highlighter; import org.sufficientlysecure.keychain.ui.util.Highlighter;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@@ -50,35 +61,21 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class ImportKeysAdapter extends RecyclerView.Adapter<ImportKeysAdapter.ViewHolder> { public class ImportKeysAdapter extends RecyclerView.Adapter<ImportKeysAdapter.ViewHolder> implements ImportKeysResultListener {
private Context mContext; private FragmentActivity mActivity;
private ImportKeysListener mListener; private ImportKeysResultListener mListener;
private boolean mNonInteractive; private boolean mNonInteractive;
private LoaderState mLoaderState; private LoaderState mLoaderState;
private List<ImportKeysListEntry> mData; private List<ImportKeysListEntry> mData;
public ImportKeysAdapter(Context mContext, ImportKeysListener listener, boolean mNonInteractive) { public ImportKeysAdapter(FragmentActivity activity, ImportKeysListener listener, boolean mNonInteractive) {
this.mContext = mContext; this.mActivity = activity;
this.mListener = listener; this.mListener = listener;
this.mNonInteractive = mNonInteractive; this.mNonInteractive = mNonInteractive;
} }
public static class ViewHolder extends RecyclerView.ViewHolder {
public ImportKeysListItemBinding binding;
public ViewHolder(View view) {
super(view);
binding = DataBindingUtil.bind(view);
}
}
public void clearData() {
mData = null;
notifyDataSetChanged();
}
public void setLoaderState(LoaderState loaderState) { public void setLoaderState(LoaderState loaderState) {
this.mLoaderState = loaderState; this.mLoaderState = loaderState;
} }
@@ -88,6 +85,11 @@ public class ImportKeysAdapter extends RecyclerView.Adapter<ImportKeysAdapter.Vi
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void clearData() {
mData = null;
notifyDataSetChanged();
}
/** /**
* This method returns a list of all selected entries, with public keys sorted * This method returns a list of all selected entries, with public keys sorted
* before secret keys, see ImportOperation for specifics. * before secret keys, see ImportOperation for specifics.
@@ -109,22 +111,31 @@ public class ImportKeysAdapter extends RecyclerView.Adapter<ImportKeysAdapter.Vi
return result; return result;
} }
public static class ViewHolder extends RecyclerView.ViewHolder {
public ImportKeysListItemBinding binding;
public ViewHolder(View view) {
super(view);
binding = DataBindingUtil.bind(view);
}
}
@Override @Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mContext); LayoutInflater inflater = LayoutInflater.from(mActivity);
View v = inflater.inflate(R.layout.import_keys_list_item, parent, false); View v = inflater.inflate(R.layout.import_keys_list_item, parent, false);
ViewHolder vh = new ViewHolder(v); ViewHolder vh = new ViewHolder(v);
return vh; return vh;
} }
@Override @Override
public void onBindViewHolder(final ViewHolder holder, int position) { public void onBindViewHolder(final ViewHolder holder, final int position) {
final ImportKeysListItemBinding b = holder.binding; final ImportKeysListItemBinding b = holder.binding;
final ImportKeysListEntry entry = mData.get(position); final ImportKeysListEntry entry = mData.get(position);
Resources resources = mContext.getResources(); Resources resources = mActivity.getResources();
Highlighter highlighter = new Highlighter(mContext, entry.getQuery()); Highlighter highlighter = new Highlighter(mActivity, entry.getQuery());
b.setStandardColor(FormattingUtils.getColorFromAttr(mContext, R.attr.colorText)); b.setStandardColor(FormattingUtils.getColorFromAttr(mActivity, R.attr.colorText));
b.setRevokedExpiredColor(resources.getColor(R.color.key_flag_gray)); b.setRevokedExpiredColor(resources.getColor(R.color.key_flag_gray));
b.setSecretColor(Color.RED); b.setSecretColor(Color.RED);
b.setHighlighter(highlighter); b.setHighlighter(highlighter);
@@ -139,94 +150,101 @@ public class ImportKeysAdapter extends RecyclerView.Adapter<ImportKeysAdapter.Vi
b.setAlgorithm(entry.getAlgorithm()); b.setAlgorithm(entry.getAlgorithm());
b.setUserId(userIdSplit.name); b.setUserId(userIdSplit.name);
b.setUserIdEmail(userIdSplit.email); b.setUserIdEmail(userIdSplit.email);
b.setKeyId(KeyFormattingUtils.beautifyKeyIdWithPrefix(mContext, entry.getKeyIdHex())); b.setKeyId(KeyFormattingUtils.beautifyKeyIdWithPrefix(mActivity, entry.getKeyIdHex()));
if (entry.isRevoked()) { if (entry.isRevoked()) {
KeyFormattingUtils.setStatusImage(mContext, b.status, null, State.REVOKED, R.color.key_flag_gray); KeyFormattingUtils.setStatusImage(mActivity, b.status, null,
State.REVOKED, R.color.key_flag_gray);
} else if (entry.isExpired()) { } else if (entry.isExpired()) {
KeyFormattingUtils.setStatusImage(mContext, b.status, null, State.EXPIRED, R.color.key_flag_gray); KeyFormattingUtils.setStatusImage(mActivity, b.status, null,
State.EXPIRED, R.color.key_flag_gray);
} }
b.importKey.setOnClickListener(new View.OnClickListener() { b.importKey.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (mLoaderState instanceof BytesLoaderState) { if (mLoaderState instanceof BytesLoaderState) {
mListener.importKey(new ParcelableKeyRing(entry.getEncodedRing())); importKey(new ParcelableKeyRing(entry.getEncodedRing()));
} else if (mLoaderState instanceof CloudLoaderState) { } else if (mLoaderState instanceof CloudLoaderState) {
mListener.importKey(new ParcelableKeyRing(entry.getFingerprintHex(), entry.getKeyIdHex(), importKey(new ParcelableKeyRing(entry.getFingerprintHex(), entry.getKeyIdHex(),
entry.getKeybaseName(), entry.getFbUsername())); entry.getKeybaseName(), entry.getFbUsername()));
} }
} }
}); });
b.expand.setOnClickListener(new View.OnClickListener() { b.expand.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
boolean hidden = b.extraContainer.getVisibility() == View.GONE; boolean hidden = b.extraContainer.getVisibility() == View.GONE;
b.extraContainer.setVisibility(hidden ? View.VISIBLE : View.GONE); b.extraContainer.setVisibility(hidden ? View.VISIBLE : View.GONE);
b.expand.animate().rotation(hidden ? 180 : 0).start(); b.expand.animate().rotation(hidden ? 180 : 0).start();
if (hidden) {
if (mLoaderState instanceof BytesLoaderState) {
getKey(new ParcelableKeyRing(entry.getEncodedRing()));
} else if (mLoaderState instanceof CloudLoaderState) {
getKey(new ParcelableKeyRing(entry.getFingerprintHex(), entry.getKeyIdHex(),
entry.getKeybaseName(), entry.getFbUsername()));
}
}
} }
}); });
if (entry.getUserIds().size() == 1) { b.userIdsList.setVisibility(entry.getUserIds().size() == 1 ? View.GONE : View.VISIBLE);
b.userIdsList.setVisibility(View.GONE); // destroyLoader view from holder
} else { b.userIdsList.removeAllViews();
b.userIdsList.setVisibility(View.VISIBLE);
// destroyLoader view from holder // we want conventional gpg UserIDs first, then Keybase ”proofs”
b.userIdsList.removeAllViews(); HashMap<String, HashSet<String>> mergedUserIds = entry.getMergedUserIds();
ArrayList<Map.Entry<String, HashSet<String>>> sortedIds = new ArrayList<Map.Entry<String, HashSet<String>>>(mergedUserIds.entrySet());
Collections.sort(sortedIds, new java.util.Comparator<Map.Entry<String, HashSet<String>>>() {
@Override
public int compare(Map.Entry<String, HashSet<String>> entry1, Map.Entry<String, HashSet<String>> entry2) {
// we want conventional gpg UserIDs first, then Keybase ”proofs” // sort keybase UserIds after non-Keybase
HashMap<String, HashSet<String>> mergedUserIds = entry.getMergedUserIds(); boolean e1IsKeybase = entry1.getKey().contains(":");
ArrayList<Map.Entry<String, HashSet<String>>> sortedIds = new ArrayList<Map.Entry<String, HashSet<String>>>(mergedUserIds.entrySet()); boolean e2IsKeybase = entry2.getKey().contains(":");
Collections.sort(sortedIds, new java.util.Comparator<Map.Entry<String, HashSet<String>>>() { if (e1IsKeybase != e2IsKeybase) {
@Override return (e1IsKeybase) ? 1 : -1;
public int compare(Map.Entry<String, HashSet<String>> entry1, Map.Entry<String, HashSet<String>> entry2) {
// sort keybase UserIds after non-Keybase
boolean e1IsKeybase = entry1.getKey().contains(":");
boolean e2IsKeybase = entry2.getKey().contains(":");
if (e1IsKeybase != e2IsKeybase) {
return (e1IsKeybase) ? 1 : -1;
}
return entry1.getKey().compareTo(entry2.getKey());
} }
}); return entry1.getKey().compareTo(entry2.getKey());
}
});
for (Map.Entry<String, HashSet<String>> pair : sortedIds) { for (Map.Entry<String, HashSet<String>> pair : sortedIds) {
String cUserId = pair.getKey(); String cUserId = pair.getKey();
HashSet<String> cEmails = pair.getValue(); HashSet<String> cEmails = pair.getValue();
LayoutInflater inflater = LayoutInflater.from(mContext); LayoutInflater inflater = LayoutInflater.from(mActivity);
TextView uidView = (TextView) inflater.inflate( TextView uidView = (TextView) inflater.inflate(
R.layout.import_keys_list_entry_user_id, null);
uidView.setText(highlighter.highlight(cUserId));
uidView.setPadding(0, 0, FormattingUtils.dpToPx(mActivity, 8), 0);
if (entry.isRevoked() || entry.isExpired()) {
uidView.setTextColor(mActivity.getResources().getColor(R.color.key_flag_gray));
} else {
uidView.setTextColor(FormattingUtils.getColorFromAttr(mActivity, R.attr.colorText));
}
b.userIdsList.addView(uidView);
for (String email : cEmails) {
TextView emailView = (TextView) inflater.inflate(
R.layout.import_keys_list_entry_user_id, null); R.layout.import_keys_list_entry_user_id, null);
uidView.setText(highlighter.highlight(cUserId)); emailView.setPadding(
uidView.setPadding(0, 0, FormattingUtils.dpToPx(mContext, 8), 0); FormattingUtils.dpToPx(mActivity, 16), 0,
FormattingUtils.dpToPx(mActivity, 8), 0);
emailView.setText(highlighter.highlight(email));
if (entry.isRevoked() || entry.isExpired()) { if (entry.isRevoked() || entry.isExpired()) {
uidView.setTextColor(mContext.getResources().getColor(R.color.key_flag_gray)); emailView.setTextColor(mActivity.getResources().getColor(R.color.key_flag_gray));
} else { } else {
uidView.setTextColor(FormattingUtils.getColorFromAttr(mContext, R.attr.colorText)); emailView.setTextColor(FormattingUtils.getColorFromAttr(mActivity, R.attr.colorText));
} }
b.userIdsList.addView(uidView); b.userIdsList.addView(emailView);
for (String email : cEmails) {
TextView emailView = (TextView) inflater.inflate(
R.layout.import_keys_list_entry_user_id, null);
emailView.setPadding(
FormattingUtils.dpToPx(mContext, 16), 0,
FormattingUtils.dpToPx(mContext, 8), 0);
emailView.setText(highlighter.highlight(email));
if (entry.isRevoked() || entry.isExpired()) {
emailView.setTextColor(mContext.getResources().getColor(R.color.key_flag_gray));
} else {
emailView.setTextColor(FormattingUtils.getColorFromAttr(mContext, R.attr.colorText));
}
b.userIdsList.addView(emailView);
}
} }
} }
} }
@@ -236,4 +254,68 @@ public class ImportKeysAdapter extends RecyclerView.Adapter<ImportKeysAdapter.Vi
return mData != null ? mData.size() : 0; return mData != null ? mData.size() : 0;
} }
public void importKey(ParcelableKeyRing keyRing) {
ImportKeyringParcel inputParcel = prepareKeyOperation(keyRing, false);
ImportKeysOperationCallback cb = new ImportKeysOperationCallback(mListener, inputParcel);
CryptoOperationHelper operationHelper = new CryptoOperationHelper(1, mActivity, cb, R.string.progress_importing);
operationHelper.cryptoOperation();
}
public void getKey(ParcelableKeyRing keyRing) {
ImportKeyringParcel inputParcel = prepareKeyOperation(keyRing, true);
ImportKeysOperationCallback cb = new ImportKeysOperationCallback(this, inputParcel);
CryptoOperationHelper operationHelper = new CryptoOperationHelper(1, mActivity, cb, R.string.progress_downloading);
operationHelper.cryptoOperation();
}
private ImportKeyringParcel prepareKeyOperation(ParcelableKeyRing keyRing, boolean skipSave) {
Log.d(Constants.TAG, "prepareKey started");
ArrayList<ParcelableKeyRing> keysList = null;
String keyserver = null;
if (mLoaderState instanceof BytesLoaderState) {
// instead of giving the entries by Intent extra, cache them into a
// file to prevent Java Binder problems on heavy imports
// read FileImportCache for more info.
try {
// We parcel this iteratively into a file - anything we can
// display here, we should be able to import.
ParcelableFileCache<ParcelableKeyRing> cache =
new ParcelableFileCache<>(mActivity, ImportOperation.CACHE_FILE_NAME);
cache.writeCache(keyRing);
} catch (IOException e) {
Log.e(Constants.TAG, "Problem writing cache file", e);
Notify.create(mActivity, "Problem writing cache file!", Notify.Style.ERROR).show();
}
} else if (mLoaderState instanceof CloudLoaderState) {
ArrayList<ParcelableKeyRing> keys = new ArrayList<>();
keys.add(keyRing);
keysList = keys;
keyserver = ((CloudLoaderState) mLoaderState).mCloudPrefs.keyserver;
}
ImportKeyringParcel keyringParcel = new ImportKeyringParcel(keysList, keyserver, skipSave);
return keyringParcel;
}
@Override
public void handleResult(ImportKeyResult result) {
boolean resultStatus = result.isOkBoth();
Log.e(Constants.TAG, "getKey result: " + resultStatus);
if (resultStatus) {
ArrayList<CanonicalizedKeyRing> canKeyRings = result.mCanonicalizedKeyRings;
int retrievedNumber = canKeyRings.size();
if (retrievedNumber == 1) {
CanonicalizedKeyRing keyRing = canKeyRings.get(0);
Log.e(Constants.TAG, "Key ID: " + keyRing.getMasterKeyId() +
"| isRev: " + keyRing.isRevoked() + "| isExp: " + keyRing.isExpired());
} else {
throw new RuntimeException("getKey retrieved more than one key.");
}
}
}
} }

View File

@@ -76,7 +76,7 @@
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text='@{userIdEmail != null ? "Key ID: " + userIdEmail : ""}' android:text='@{keyId != null ? "Key ID: " + keyId : ""}'
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@{revoked || expired ? revokedExpiredColor : standardColor}" /> android:textColor="@{revoked || expired ? revokedExpiredColor : standardColor}" />

View File

@@ -419,6 +419,7 @@
<string name="progress_done">"Done."</string> <string name="progress_done">"Done."</string>
<string name="progress_cancel">"Cancel"</string> <string name="progress_cancel">"Cancel"</string>
<string name="progress_cancelling">"cancelling…"</string> <string name="progress_cancelling">"cancelling…"</string>
<string name="progress_downloading">"downloading…"</string>
<string name="progress_saving">"saving…"</string> <string name="progress_saving">"saving…"</string>
<string name="progress_importing">"importing…"</string> <string name="progress_importing">"importing…"</string>
<string name="progress_benchmarking">"benchmarking…"</string> <string name="progress_benchmarking">"benchmarking…"</string>