Merge pull request #1362 from open-keychain/operation-migration
Migrated all operations to KeychainNewService
This commit is contained in:
@@ -709,9 +709,6 @@
|
|||||||
android:name=".remote.CryptoInputParcelCacheService"
|
android:name=".remote.CryptoInputParcelCacheService"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:process=":remote_api" />
|
android:process=":remote_api" />
|
||||||
<service
|
|
||||||
android:name=".service.KeychainNewService"
|
|
||||||
android:exported="false" />
|
|
||||||
<service
|
<service
|
||||||
android:name=".service.KeychainService"
|
android:name=".service.KeychainService"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|||||||
@@ -58,12 +58,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
* @see CertifyActionsParcel
|
* @see CertifyActionsParcel
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class CertifyOperation extends BaseOperation {
|
public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
|
||||||
|
|
||||||
public CertifyOperation(Context context, ProviderHelper providerHelper, Progressable progressable, AtomicBoolean cancelled) {
|
public CertifyOperation(Context context, ProviderHelper providerHelper, Progressable progressable, AtomicBoolean cancelled) {
|
||||||
super(context, providerHelper, progressable, cancelled);
|
super(context, providerHelper, progressable, cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public CertifyResult execute(CertifyActionsParcel parcel, CryptoInputParcel cryptoInput) {
|
public CertifyResult execute(CertifyActionsParcel parcel, CryptoInputParcel cryptoInput) {
|
||||||
|
|
||||||
OperationLog log = new OperationLog();
|
OperationLog log = new OperationLog();
|
||||||
@@ -86,8 +87,10 @@ public class CertifyOperation extends BaseOperation {
|
|||||||
case PATTERN:
|
case PATTERN:
|
||||||
case PASSPHRASE:
|
case PASSPHRASE:
|
||||||
if (!cryptoInput.hasPassphrase()) {
|
if (!cryptoInput.hasPassphrase()) {
|
||||||
return new CertifyResult(log, RequiredInputParcel.createRequiredSignPassphrase(
|
return new CertifyResult(log,
|
||||||
certificationKey.getKeyId(), certificationKey.getKeyId(), null));
|
RequiredInputParcel.createRequiredSignPassphrase(
|
||||||
|
certificationKey.getKeyId(), certificationKey.getKeyId(), null)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// certification is always with the master key id, so use that one
|
// certification is always with the master key id, so use that one
|
||||||
passphrase = cryptoInput.getPassphrase();
|
passphrase = cryptoInput.getPassphrase();
|
||||||
@@ -185,10 +188,10 @@ public class CertifyOperation extends BaseOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HkpKeyserver keyServer = null;
|
HkpKeyserver keyServer = null;
|
||||||
ImportExportOperation importExportOperation = null;
|
ExportOperation exportOperation = null;
|
||||||
if (parcel.keyServerUri != null) {
|
if (parcel.keyServerUri != null) {
|
||||||
keyServer = new HkpKeyserver(parcel.keyServerUri);
|
keyServer = new HkpKeyserver(parcel.keyServerUri);
|
||||||
importExportOperation = new ImportExportOperation(mContext, mProviderHelper, mProgressable);
|
exportOperation = new ExportOperation(mContext, mProviderHelper, mProgressable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write all certified keys into the database
|
// Write all certified keys into the database
|
||||||
@@ -206,10 +209,10 @@ public class CertifyOperation extends BaseOperation {
|
|||||||
mProviderHelper.clearLog();
|
mProviderHelper.clearLog();
|
||||||
SaveKeyringResult result = mProviderHelper.savePublicKeyRing(certifiedKey);
|
SaveKeyringResult result = mProviderHelper.savePublicKeyRing(certifiedKey);
|
||||||
|
|
||||||
if (importExportOperation != null) {
|
if (exportOperation != null) {
|
||||||
// TODO use subresult, get rid of try/catch!
|
// TODO use subresult, get rid of try/catch!
|
||||||
try {
|
try {
|
||||||
importExportOperation.uploadKeyRingToServer(keyServer, certifiedKey);
|
exportOperation.uploadKeyRingToServer(keyServer, certifiedKey);
|
||||||
uploadOk += 1;
|
uploadOk += 1;
|
||||||
} catch (AddKeyException e) {
|
} catch (AddKeyException e) {
|
||||||
Log.e(Constants.TAG, "error uploading key", e);
|
Log.e(Constants.TAG, "error uploading key", e);
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||||
|
* Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.operations;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||||
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
import org.sufficientlysecure.keychain.service.ConsolidateInputParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
|
|
||||||
|
public class ConsolidateOperation extends BaseOperation<ConsolidateInputParcel> {
|
||||||
|
|
||||||
|
public ConsolidateOperation(Context context, ProviderHelper providerHelper, Progressable
|
||||||
|
progressable) {
|
||||||
|
super(context, providerHelper, progressable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConsolidateResult execute(ConsolidateInputParcel consolidateInputParcel,
|
||||||
|
CryptoInputParcel cryptoInputParcel) {
|
||||||
|
if (consolidateInputParcel.mConsolidateRecovery) {
|
||||||
|
return mProviderHelper.consolidateDatabaseStep2(mProgressable);
|
||||||
|
} else {
|
||||||
|
return mProviderHelper.consolidateDatabaseStep1(mProgressable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,8 @@ import org.sufficientlysecure.keychain.pgp.Progressable;
|
|||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
|
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
|
||||||
|
import org.sufficientlysecure.keychain.service.DeleteKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
|
||||||
/** An operation which implements a high level keyring delete operation.
|
/** An operation which implements a high level keyring delete operation.
|
||||||
@@ -37,13 +39,18 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
|||||||
* a list.
|
* a list.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class DeleteOperation extends BaseOperation {
|
public class DeleteOperation extends BaseOperation<DeleteKeyringParcel> {
|
||||||
|
|
||||||
public DeleteOperation(Context context, ProviderHelper providerHelper, Progressable progressable) {
|
public DeleteOperation(Context context, ProviderHelper providerHelper, Progressable progressable) {
|
||||||
super(context, providerHelper, progressable);
|
super(context, providerHelper, progressable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeleteResult execute(long[] masterKeyIds, boolean isSecret) {
|
@Override
|
||||||
|
public DeleteResult execute(DeleteKeyringParcel deleteKeyringParcel,
|
||||||
|
CryptoInputParcel cryptoInputParcel) {
|
||||||
|
|
||||||
|
long[] masterKeyIds = deleteKeyringParcel.mMasterKeyIds;
|
||||||
|
boolean isSecret = deleteKeyringParcel.mIsSecret;
|
||||||
|
|
||||||
OperationLog log = new OperationLog();
|
OperationLog log = new OperationLog();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,343 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.operations;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import org.spongycastle.bcpg.ArmoredOutputStream;
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
|
||||||
|
import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
||||||
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An operation class which implements high level export
|
||||||
|
* operations.
|
||||||
|
* This class receives a source and/or destination of keys as input and performs
|
||||||
|
* all steps for this export.
|
||||||
|
*
|
||||||
|
* @see org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter#getSelectedEntries()
|
||||||
|
* For the export operation, the input consists of a set of key ids and
|
||||||
|
* either the name of a file or an output uri to write to.
|
||||||
|
* TODO rework uploadKeyRingToServer
|
||||||
|
*/
|
||||||
|
public class ExportOperation extends BaseOperation<ExportKeyringParcel> {
|
||||||
|
|
||||||
|
public ExportOperation(Context context, ProviderHelper providerHelper, Progressable
|
||||||
|
progressable) {
|
||||||
|
super(context, providerHelper, progressable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportOperation(Context context, ProviderHelper providerHelper,
|
||||||
|
Progressable progressable, AtomicBoolean cancelled) {
|
||||||
|
super(context, providerHelper, progressable, cancelled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring)
|
||||||
|
throws AddKeyException {
|
||||||
|
uploadKeyRingToServer(server, keyring.getUncachedKeyRing());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void uploadKeyRingToServer(HkpKeyserver server, UncachedKeyRing keyring) throws
|
||||||
|
AddKeyException {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
ArmoredOutputStream aos = null;
|
||||||
|
try {
|
||||||
|
aos = new ArmoredOutputStream(bos);
|
||||||
|
keyring.encode(aos);
|
||||||
|
aos.close();
|
||||||
|
|
||||||
|
String armoredKey = bos.toString("UTF-8");
|
||||||
|
server.add(armoredKey);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "IOException", e);
|
||||||
|
throw new AddKeyException();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (aos != null) {
|
||||||
|
aos.close();
|
||||||
|
}
|
||||||
|
bos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// this is just a finally thing, no matter if it doesn't work out.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportResult exportToFile(long[] masterKeyIds, boolean exportSecret, String outputFile) {
|
||||||
|
|
||||||
|
OperationLog log = new OperationLog();
|
||||||
|
if (masterKeyIds != null) {
|
||||||
|
log.add(LogType.MSG_EXPORT, 0, masterKeyIds.length);
|
||||||
|
} else {
|
||||||
|
log.add(LogType.MSG_EXPORT_ALL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// do we have a file name?
|
||||||
|
if (outputFile == null) {
|
||||||
|
log.add(LogType.MSG_EXPORT_ERROR_NO_FILE, 1);
|
||||||
|
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if storage is ready
|
||||||
|
if (!FileHelper.isStorageMounted(outputFile)) {
|
||||||
|
log.add(LogType.MSG_EXPORT_ERROR_STORAGE, 1);
|
||||||
|
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
OutputStream outStream = new FileOutputStream(outputFile);
|
||||||
|
try {
|
||||||
|
ExportResult result = exportKeyRings(log, masterKeyIds, exportSecret, outStream);
|
||||||
|
if (result.cancelled()) {
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
|
new File(outputFile).delete();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
outStream.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.add(LogType.MSG_EXPORT_ERROR_FOPEN, 1);
|
||||||
|
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportResult exportToUri(long[] masterKeyIds, boolean exportSecret, Uri outputUri) {
|
||||||
|
|
||||||
|
OperationLog log = new OperationLog();
|
||||||
|
if (masterKeyIds != null) {
|
||||||
|
log.add(LogType.MSG_EXPORT, 0, masterKeyIds.length);
|
||||||
|
} else {
|
||||||
|
log.add(LogType.MSG_EXPORT_ALL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// do we have a file name?
|
||||||
|
if (outputUri == null) {
|
||||||
|
log.add(LogType.MSG_EXPORT_ERROR_NO_URI, 1);
|
||||||
|
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
OutputStream outStream = mProviderHelper.getContentResolver().openOutputStream
|
||||||
|
(outputUri);
|
||||||
|
return exportKeyRings(log, masterKeyIds, exportSecret, outStream);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
log.add(LogType.MSG_EXPORT_ERROR_URI_OPEN, 1);
|
||||||
|
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportResult exportKeyRings(OperationLog log, long[] masterKeyIds, boolean exportSecret,
|
||||||
|
OutputStream outStream) {
|
||||||
|
|
||||||
|
/* TODO isn't this checked above, with the isStorageMounted call?
|
||||||
|
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||||
|
log.add(LogType.MSG_EXPORT_ERROR_STORAGE, 1);
|
||||||
|
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!BufferedOutputStream.class.isInstance(outStream)) {
|
||||||
|
outStream = new BufferedOutputStream(outStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int okSecret = 0, okPublic = 0, progress = 0;
|
||||||
|
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
|
||||||
|
String selection = null, ids[] = null;
|
||||||
|
|
||||||
|
if (masterKeyIds != null) {
|
||||||
|
// generate placeholders and string selection args
|
||||||
|
ids = new String[masterKeyIds.length];
|
||||||
|
StringBuilder placeholders = new StringBuilder("?");
|
||||||
|
for (int i = 0; i < masterKeyIds.length; i++) {
|
||||||
|
ids[i] = Long.toString(masterKeyIds[i]);
|
||||||
|
if (i != 0) {
|
||||||
|
placeholders.append(",?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// put together selection string
|
||||||
|
selection = Tables.KEY_RINGS_PUBLIC + "." + KeyRings.MASTER_KEY_ID
|
||||||
|
+ " IN (" + placeholders + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = mProviderHelper.getContentResolver().query(
|
||||||
|
KeyRings.buildUnifiedKeyRingsUri(), new String[]{
|
||||||
|
KeyRings.MASTER_KEY_ID, KeyRings.PUBKEY_DATA,
|
||||||
|
KeyRings.PRIVKEY_DATA, KeyRings.HAS_ANY_SECRET
|
||||||
|
}, selection, ids, Tables.KEYS + "." + KeyRings.MASTER_KEY_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cursor == null || !cursor.moveToFirst()) {
|
||||||
|
log.add(LogType.MSG_EXPORT_ERROR_DB, 1);
|
||||||
|
return new ExportResult(ExportResult.RESULT_ERROR, log, okPublic, okSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int numKeys = cursor.getCount();
|
||||||
|
|
||||||
|
updateProgress(
|
||||||
|
mContext.getResources().getQuantityString(R.plurals.progress_exporting_key,
|
||||||
|
numKeys), 0, numKeys);
|
||||||
|
|
||||||
|
// For each public masterKey id
|
||||||
|
while (!cursor.isAfterLast()) {
|
||||||
|
|
||||||
|
long keyId = cursor.getLong(0);
|
||||||
|
ArmoredOutputStream arOutStream = null;
|
||||||
|
|
||||||
|
// Create an output stream
|
||||||
|
try {
|
||||||
|
arOutStream = new ArmoredOutputStream(outStream);
|
||||||
|
|
||||||
|
log.add(LogType.MSG_EXPORT_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(keyId));
|
||||||
|
|
||||||
|
byte[] data = cursor.getBlob(1);
|
||||||
|
CanonicalizedKeyRing ring =
|
||||||
|
UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true);
|
||||||
|
ring.encode(arOutStream);
|
||||||
|
|
||||||
|
okPublic += 1;
|
||||||
|
} catch (PgpGeneralException e) {
|
||||||
|
log.add(LogType.MSG_EXPORT_ERROR_KEY, 2);
|
||||||
|
updateProgress(progress++, numKeys);
|
||||||
|
continue;
|
||||||
|
} finally {
|
||||||
|
// make sure this is closed
|
||||||
|
if (arOutStream != null) {
|
||||||
|
arOutStream.close();
|
||||||
|
}
|
||||||
|
arOutStream = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exportSecret && cursor.getInt(3) > 0) {
|
||||||
|
try {
|
||||||
|
arOutStream = new ArmoredOutputStream(outStream);
|
||||||
|
|
||||||
|
// export secret key part
|
||||||
|
log.add(LogType.MSG_EXPORT_SECRET, 2, KeyFormattingUtils.beautifyKeyId
|
||||||
|
(keyId));
|
||||||
|
byte[] data = cursor.getBlob(2);
|
||||||
|
CanonicalizedKeyRing ring =
|
||||||
|
UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true);
|
||||||
|
ring.encode(arOutStream);
|
||||||
|
|
||||||
|
okSecret += 1;
|
||||||
|
} catch (PgpGeneralException e) {
|
||||||
|
log.add(LogType.MSG_EXPORT_ERROR_KEY, 2);
|
||||||
|
updateProgress(progress++, numKeys);
|
||||||
|
continue;
|
||||||
|
} finally {
|
||||||
|
// make sure this is closed
|
||||||
|
if (arOutStream != null) {
|
||||||
|
arOutStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProgress(progress++, numKeys);
|
||||||
|
|
||||||
|
cursor.moveToNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProgress(R.string.progress_done, numKeys, numKeys);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.add(LogType.MSG_EXPORT_ERROR_IO, 1);
|
||||||
|
return new ExportResult(ExportResult.RESULT_ERROR, log, okPublic, okSecret);
|
||||||
|
} finally {
|
||||||
|
// Make sure the stream is closed
|
||||||
|
if (outStream != null) try {
|
||||||
|
outStream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(Constants.TAG, "error closing stream", e);
|
||||||
|
}
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
log.add(LogType.MSG_EXPORT_SUCCESS, 1);
|
||||||
|
return new ExportResult(ExportResult.RESULT_OK, log, okPublic, okSecret);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportResult execute(ExportKeyringParcel exportInput, CryptoInputParcel cryptoInput) {
|
||||||
|
switch (exportInput.mExportType) {
|
||||||
|
case UPLOAD_KEYSERVER: {
|
||||||
|
HkpKeyserver hkpKeyserver = new HkpKeyserver(exportInput.mKeyserver);
|
||||||
|
try {
|
||||||
|
CanonicalizedPublicKeyRing keyring
|
||||||
|
= mProviderHelper.getCanonicalizedPublicKeyRing(
|
||||||
|
exportInput.mCanonicalizedPublicKeyringUri);
|
||||||
|
uploadKeyRingToServer(hkpKeyserver, keyring);
|
||||||
|
// TODO: replace with proper log
|
||||||
|
return new ExportResult(ExportResult.RESULT_OK, new OperationLog());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new ExportResult(ExportResult.RESULT_ERROR, new OperationLog());
|
||||||
|
// TODO: Implement better exception handling, replace with log
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case EXPORT_FILE: {
|
||||||
|
return exportToFile(exportInput.mMasterKeyIds, exportInput.mExportSecret,
|
||||||
|
exportInput.mOutputFile);
|
||||||
|
}
|
||||||
|
case EXPORT_URI: {
|
||||||
|
return exportToUri(exportInput.mMasterKeyIds, exportInput.mExportSecret,
|
||||||
|
exportInput.mOutputUri);
|
||||||
|
}
|
||||||
|
default: { // can't happen
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,57 +19,50 @@
|
|||||||
package org.sufficientlysecure.keychain.operations;
|
package org.sufficientlysecure.keychain.operations;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
import org.spongycastle.bcpg.ArmoredOutputStream;
|
|
||||||
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.HkpKeyserver;
|
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
|
||||||
import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver;
|
import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver;
|
||||||
import org.sufficientlysecure.keychain.keyimport.Keyserver;
|
import org.sufficientlysecure.keychain.keyimport.Keyserver;
|
||||||
import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException;
|
|
||||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
|
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
|
||||||
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.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.CanonicalizedPublicKeyRing;
|
|
||||||
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;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
|
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
|
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
|
||||||
import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize;
|
import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorCompletionService;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.SynchronousQueue;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/** An operation class which implements high level import and export
|
/**
|
||||||
|
* An operation class which implements high level import
|
||||||
* operations.
|
* operations.
|
||||||
*
|
|
||||||
* This class receives a source and/or destination of keys as input and performs
|
* This class receives a source and/or destination of keys as input and performs
|
||||||
* all steps for this import or export.
|
* all steps for this import.
|
||||||
*
|
|
||||||
* For the import operation, the only valid source is an Iterator of
|
* For the import operation, the only valid source is an Iterator of
|
||||||
* ParcelableKeyRing, each of which must contain either a single
|
* ParcelableKeyRing, each of which must contain either a single
|
||||||
* keyring encoded as bytes, or a unique reference to a keyring
|
* keyring encoded as bytes, or a unique reference to a keyring
|
||||||
@@ -78,72 +71,57 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
* secret keys, because some implementations (notably Symantec PGP Desktop) do
|
* secret keys, because some implementations (notably Symantec PGP Desktop) do
|
||||||
* 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()
|
* @see org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter#getSelectedEntries()
|
||||||
*
|
|
||||||
* For the export operation, the input consists of a set of key ids and
|
|
||||||
* either the name of a file or an output uri to write to.
|
|
||||||
*
|
|
||||||
* TODO rework uploadKeyRingToServer
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class ImportExportOperation extends BaseOperation {
|
public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
|
||||||
|
|
||||||
public ImportExportOperation(Context context, ProviderHelper providerHelper, Progressable progressable) {
|
public ImportOperation(Context context, ProviderHelper providerHelper, Progressable
|
||||||
|
progressable) {
|
||||||
super(context, providerHelper, progressable);
|
super(context, providerHelper, progressable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImportExportOperation(Context context, ProviderHelper providerHelper,
|
public ImportOperation(Context context, ProviderHelper providerHelper,
|
||||||
Progressable progressable, AtomicBoolean cancelled) {
|
Progressable progressable, AtomicBoolean cancelled) {
|
||||||
super(context, providerHelper, progressable, cancelled);
|
super(context, providerHelper, progressable, cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring) throws AddKeyException {
|
// Overloaded functions for using progressable supplied in constructor during import
|
||||||
uploadKeyRingToServer(server, keyring.getUncachedKeyRing());
|
public ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num,
|
||||||
|
String keyServerUri) {
|
||||||
|
return serialKeyRingImport(entries, num, keyServerUri, mProgressable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void uploadKeyRingToServer(HkpKeyserver server, UncachedKeyRing keyring) throws AddKeyException {
|
public ImportKeyResult serialKeyRingImport(List<ParcelableKeyRing> entries,
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
String keyServerUri) {
|
||||||
ArmoredOutputStream aos = null;
|
|
||||||
try {
|
|
||||||
aos = new ArmoredOutputStream(bos);
|
|
||||||
keyring.encode(aos);
|
|
||||||
aos.close();
|
|
||||||
|
|
||||||
String armoredKey = bos.toString("UTF-8");
|
|
||||||
server.add(armoredKey);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(Constants.TAG, "IOException", e);
|
|
||||||
throw new AddKeyException();
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (aos != null) {
|
|
||||||
aos.close();
|
|
||||||
}
|
|
||||||
bos.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// this is just a finally thing, no matter if it doesn't work out.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImportKeyResult importKeyRings(List<ParcelableKeyRing> entries, String keyServerUri) {
|
|
||||||
|
|
||||||
Iterator<ParcelableKeyRing> it = entries.iterator();
|
Iterator<ParcelableKeyRing> it = entries.iterator();
|
||||||
int numEntries = entries.size();
|
int numEntries = entries.size();
|
||||||
|
|
||||||
return importKeyRings(it, numEntries, keyServerUri);
|
return serialKeyRingImport(it, numEntries, keyServerUri, mProgressable);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImportKeyResult importKeyRings(ParcelableFileCache<ParcelableKeyRing> cache, String keyServerUri) {
|
public ImportKeyResult serialKeyRingImport(List<ParcelableKeyRing> entries, String keyServerUri,
|
||||||
|
Progressable progressable) {
|
||||||
|
|
||||||
|
Iterator<ParcelableKeyRing> it = entries.iterator();
|
||||||
|
int numEntries = entries.size();
|
||||||
|
|
||||||
|
return serialKeyRingImport(it, numEntries, keyServerUri, progressable);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImportKeyResult serialKeyRingImport(ParcelableFileCache<ParcelableKeyRing> cache,
|
||||||
|
String keyServerUri) {
|
||||||
|
|
||||||
// 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 importKeyRings(it, numEntries, keyServerUri);
|
return serialKeyRingImport(it, numEntries, keyServerUri, mProgressable);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
||||||
// Special treatment here, we need a lot
|
// Special treatment here, we need a lot
|
||||||
@@ -157,15 +135,18 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Since the introduction of multithreaded import, we expect calling functions to handle the key sync i,e
|
* Since the introduction of multithreaded import, we expect calling functions to handle the
|
||||||
* ContactSyncAdapterService.requestSync()
|
* key sync i,eContactSyncAdapterService.requestSync()
|
||||||
*
|
*
|
||||||
* @param entries keys to import
|
* @param entries keys to import
|
||||||
* @param num number of keys to import
|
* @param num number of keys to import
|
||||||
* @param keyServerUri contains uri of keyserver to import from, if it is an import from cloud
|
* @param keyServerUri contains uri of keyserver to import from, if it is an import from cloud
|
||||||
|
* @param progressable Allows multi-threaded import to supply a progressable that ignores the
|
||||||
|
* progress of a single key being imported
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public ImportKeyResult importKeyRings(Iterator<ParcelableKeyRing> entries, int num, String keyServerUri) {
|
public ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num,
|
||||||
|
String keyServerUri, Progressable progressable) {
|
||||||
updateProgress(R.string.progress_importing, 0, 100);
|
updateProgress(R.string.progress_importing, 0, 100);
|
||||||
|
|
||||||
OperationLog log = new OperationLog();
|
OperationLog log = new OperationLog();
|
||||||
@@ -208,7 +189,8 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
else {
|
else {
|
||||||
|
|
||||||
// We fetch from keyservers first, because we tend to get more certificates
|
// We fetch from keyservers first, because we tend to get more certificates
|
||||||
// from there, so the number of certificates which are merged in later is smaller.
|
// from there, so the number of certificates which are merged in later is
|
||||||
|
// smaller.
|
||||||
|
|
||||||
// If we have a keyServerUri and a fingerprint or at least a keyId,
|
// If we have a keyServerUri and a fingerprint or at least a keyId,
|
||||||
// download from HKP
|
// download from HKP
|
||||||
@@ -224,7 +206,8 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
byte[] data;
|
byte[] data;
|
||||||
// Download by fingerprint, or keyId - whichever is available
|
// Download by fingerprint, or keyId - whichever is available
|
||||||
if (entry.mExpectedFingerprint != null) {
|
if (entry.mExpectedFingerprint != null) {
|
||||||
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, "0x" + entry.mExpectedFingerprint.substring(24));
|
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, "0x" +
|
||||||
|
entry.mExpectedFingerprint.substring(24));
|
||||||
data = keyServer.get("0x" + entry.mExpectedFingerprint).getBytes();
|
data = keyServer.get("0x" + entry.mExpectedFingerprint).getBytes();
|
||||||
} else {
|
} else {
|
||||||
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, entry.mKeyIdHex);
|
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, entry.mKeyIdHex);
|
||||||
@@ -302,10 +285,12 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
mProviderHelper.clearLog();
|
mProviderHelper.clearLog();
|
||||||
if (key.isSecret()) {
|
if (key.isSecret()) {
|
||||||
result = mProviderHelper.saveSecretKeyRing(key,
|
result = mProviderHelper.saveSecretKeyRing(key,
|
||||||
new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
|
new ProgressScaler(progressable, (int) (position * progSteps),
|
||||||
|
(int) ((position + 1) * progSteps), 100));
|
||||||
} else {
|
} else {
|
||||||
result = mProviderHelper.savePublicKeyRing(key,
|
result = mProviderHelper.savePublicKeyRing(key,
|
||||||
new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
|
new ProgressScaler(progressable, (int) (position * progSteps),
|
||||||
|
(int) ((position + 1) * progSteps), 100));
|
||||||
}
|
}
|
||||||
if (!result.success()) {
|
if (!result.success()) {
|
||||||
badKeys += 1;
|
badKeys += 1;
|
||||||
@@ -333,7 +318,7 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
// Special: consolidate on secret key import (cannot be cancelled!)
|
// Special: consolidate on secret key import (cannot be cancelled!)
|
||||||
if (secret > 0) {
|
if (secret > 0) {
|
||||||
setPreventCancel();
|
setPreventCancel();
|
||||||
ConsolidateResult result = mProviderHelper.consolidateDatabaseStep1(mProgressable);
|
ConsolidateResult result = mProviderHelper.consolidateDatabaseStep1(progressable);
|
||||||
log.add(result, 1);
|
log.add(result, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,7 +361,7 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Final log entry, it's easier to do this individually
|
// Final log entry, it's easier to do this individually
|
||||||
if ( (newKeys > 0 || updatedKeys > 0) && badKeys > 0) {
|
if ((newKeys > 0 || updatedKeys > 0) && badKeys > 0) {
|
||||||
log.add(LogType.MSG_IMPORT_PARTIAL, 1);
|
log.add(LogType.MSG_IMPORT_PARTIAL, 1);
|
||||||
} else if (newKeys > 0 || updatedKeys > 0) {
|
} else if (newKeys > 0 || updatedKeys > 0) {
|
||||||
log.add(LogType.MSG_IMPORT_SUCCESS, 1);
|
log.add(LogType.MSG_IMPORT_SUCCESS, 1);
|
||||||
@@ -388,206 +373,193 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
importedMasterKeyIdsArray);
|
importedMasterKeyIdsArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExportResult exportToFile(long[] masterKeyIds, boolean exportSecret, String outputFile) {
|
@Override
|
||||||
|
public ImportKeyResult execute(ImportKeyringParcel importInput, CryptoInputParcel cryptoInput) {
|
||||||
|
return importKeys(importInput.mKeyList, importInput.mKeyserver);
|
||||||
|
}
|
||||||
|
|
||||||
OperationLog log = new OperationLog();
|
public ImportKeyResult importKeys(ArrayList<ParcelableKeyRing> keyList, String keyServer) {
|
||||||
if (masterKeyIds != null) {
|
|
||||||
log.add(LogType.MSG_EXPORT, 0, masterKeyIds.length);
|
ImportKeyResult result;
|
||||||
|
|
||||||
|
if (keyList == null) {// import from file, do serially
|
||||||
|
ParcelableFileCache<ParcelableKeyRing> cache = new ParcelableFileCache<>(mContext,
|
||||||
|
"key_import.pcl");
|
||||||
|
|
||||||
|
result = serialKeyRingImport(cache, keyServer);
|
||||||
} else {
|
} else {
|
||||||
log.add(LogType.MSG_EXPORT_ALL, 0);
|
// if there is more than one key with the same fingerprint, we do a serial import to
|
||||||
|
// prevent
|
||||||
|
// https://github.com/open-keychain/open-keychain/issues/1221
|
||||||
|
HashSet<String> keyFingerprintSet = new HashSet<>();
|
||||||
|
for (int i = 0; i < keyList.size(); i++) {
|
||||||
|
keyFingerprintSet.add(keyList.get(i).mExpectedFingerprint);
|
||||||
|
}
|
||||||
|
if (keyFingerprintSet.size() == keyList.size()) {
|
||||||
|
// all keys have unique fingerprints
|
||||||
|
result = multiThreadedKeyImport(keyList.iterator(), keyList.size(), keyServer);
|
||||||
|
} else {
|
||||||
|
result = serialKeyRingImport(keyList, keyServer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// do we have a file name?
|
ContactSyncAdapterService.requestSync();
|
||||||
if (outputFile == null) {
|
|
||||||
log.add(LogType.MSG_EXPORT_ERROR_NO_FILE, 1);
|
|
||||||
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if storage is ready
|
|
||||||
if (!FileHelper.isStorageMounted(outputFile)) {
|
|
||||||
log.add(LogType.MSG_EXPORT_ERROR_STORAGE, 1);
|
|
||||||
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
OutputStream outStream = new FileOutputStream(outputFile);
|
|
||||||
try {
|
|
||||||
ExportResult result = exportKeyRings(log, masterKeyIds, exportSecret, outStream);
|
|
||||||
if (result.cancelled()) {
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
new File(outputFile).delete();
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
} finally {
|
|
||||||
outStream.close();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.add(LogType.MSG_EXPORT_ERROR_FOPEN, 1);
|
|
||||||
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ImportKeyResult multiThreadedKeyImport(Iterator<ParcelableKeyRing> keyListIterator,
|
||||||
|
int totKeys, final String keyServer) {
|
||||||
|
Log.d(Constants.TAG, "Multi-threaded key import starting");
|
||||||
|
if (keyListIterator != null) {
|
||||||
|
KeyImportAccumulator accumulator = new KeyImportAccumulator(totKeys, mProgressable);
|
||||||
|
|
||||||
|
final ProgressScaler ignoreProgressable = new ProgressScaler();
|
||||||
|
|
||||||
|
final int maxThreads = 200;
|
||||||
|
ExecutorService importExecutor = new ThreadPoolExecutor(0, maxThreads,
|
||||||
|
30L, TimeUnit.SECONDS,
|
||||||
|
new SynchronousQueue<Runnable>());
|
||||||
|
|
||||||
|
ExecutorCompletionService<ImportKeyResult> importCompletionService =
|
||||||
|
new ExecutorCompletionService(importExecutor);
|
||||||
|
|
||||||
|
while (keyListIterator.hasNext()) { // submit all key rings to be imported
|
||||||
|
|
||||||
|
final ParcelableKeyRing pkRing = keyListIterator.next();
|
||||||
|
|
||||||
|
Callable<ImportKeyResult> importOperationCallable = new Callable<ImportKeyResult>
|
||||||
|
() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImportKeyResult call() {
|
||||||
|
|
||||||
|
ArrayList<ParcelableKeyRing> list = new ArrayList<>();
|
||||||
|
list.add(pkRing);
|
||||||
|
|
||||||
|
return serialKeyRingImport(list, keyServer, ignoreProgressable);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
importCompletionService.submit(importOperationCallable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExportResult exportToUri(long[] masterKeyIds, boolean exportSecret, Uri outputUri) {
|
while (!accumulator.isImportFinished()) { // accumulate the results of each import
|
||||||
|
|
||||||
OperationLog log = new OperationLog();
|
|
||||||
if (masterKeyIds != null) {
|
|
||||||
log.add(LogType.MSG_EXPORT, 0, masterKeyIds.length);
|
|
||||||
} else {
|
|
||||||
log.add(LogType.MSG_EXPORT_ALL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// do we have a file name?
|
|
||||||
if (outputUri == null) {
|
|
||||||
log.add(LogType.MSG_EXPORT_ERROR_NO_URI, 1);
|
|
||||||
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OutputStream outStream = mProviderHelper.getContentResolver().openOutputStream(outputUri);
|
accumulator.accumulateKeyImport(importCompletionService.take().get());
|
||||||
return exportKeyRings(log, masterKeyIds, exportSecret, outStream);
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
} catch (FileNotFoundException e) {
|
Log.e(Constants.TAG, "A key could not be imported during multi-threaded " +
|
||||||
log.add(LogType.MSG_EXPORT_ERROR_URI_OPEN, 1);
|
"import", e);
|
||||||
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
// do nothing?
|
||||||
|
if (e instanceof ExecutionException) {
|
||||||
|
// Since serialKeyRingImport does not throw any exceptions, this is what
|
||||||
|
// would have happened if
|
||||||
|
// we were importing the key on this thread
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accumulator.getConsolidatedResult();
|
||||||
|
}
|
||||||
|
return null; // TODO: Decide if we should just crash instead of returning null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Used to accumulate the results of individual key imports
|
||||||
ExportResult exportKeyRings(OperationLog log, long[] masterKeyIds, boolean exportSecret,
|
|
||||||
OutputStream outStream) {
|
|
||||||
|
|
||||||
/* TODO isn't this checked above, with the isStorageMounted call?
|
|
||||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
|
||||||
log.add(LogType.MSG_EXPORT_ERROR_STORAGE, 1);
|
|
||||||
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
private class KeyImportAccumulator {
|
||||||
|
private OperationResult.OperationLog mImportLog = new OperationResult.OperationLog();
|
||||||
|
Progressable mProgressable;
|
||||||
|
private int mTotalKeys;
|
||||||
|
private int mImportedKeys = 0;
|
||||||
|
ArrayList<Long> mImportedMasterKeyIds = new ArrayList<Long>();
|
||||||
|
private int mBadKeys = 0;
|
||||||
|
private int mNewKeys = 0;
|
||||||
|
private int mUpdatedKeys = 0;
|
||||||
|
private int mSecret = 0;
|
||||||
|
private int mResultType = 0;
|
||||||
|
|
||||||
if ( ! BufferedOutputStream.class.isInstance(outStream)) {
|
/**
|
||||||
outStream = new BufferedOutputStream(outStream);
|
* Accumulates keyring imports and updates the progressable whenever a new key is imported.
|
||||||
|
* Also sets the progress to 0 on instantiation.
|
||||||
|
*
|
||||||
|
* @param totalKeys total number of keys to be imported
|
||||||
|
* @param externalProgressable the external progressable to be updated every time a key
|
||||||
|
* is imported
|
||||||
|
*/
|
||||||
|
public KeyImportAccumulator(int totalKeys, Progressable externalProgressable) {
|
||||||
|
mTotalKeys = totalKeys;
|
||||||
|
mProgressable = externalProgressable;
|
||||||
|
mProgressable.setProgress(0, totalKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
int okSecret = 0, okPublic = 0, progress = 0;
|
public int getTotalKeys() {
|
||||||
|
return mTotalKeys;
|
||||||
|
}
|
||||||
|
|
||||||
Cursor cursor = null;
|
public int getImportedKeys() {
|
||||||
try {
|
return mImportedKeys;
|
||||||
|
}
|
||||||
|
|
||||||
String selection = null, ids[] = null;
|
public synchronized void accumulateKeyImport(ImportKeyResult result) {
|
||||||
|
mImportedKeys++;
|
||||||
|
|
||||||
if (masterKeyIds != null) {
|
mProgressable.setProgress(mImportedKeys, mTotalKeys);
|
||||||
// generate placeholders and string selection args
|
|
||||||
ids = new String[masterKeyIds.length];
|
mImportLog.addAll(result.getLog().toList());//accumulates log
|
||||||
StringBuilder placeholders = new StringBuilder("?");
|
mBadKeys += result.mBadKeys;
|
||||||
|
mNewKeys += result.mNewKeys;
|
||||||
|
mUpdatedKeys += result.mUpdatedKeys;
|
||||||
|
mSecret += result.mSecret;
|
||||||
|
|
||||||
|
long[] masterKeyIds = result.getImportedMasterKeyIds();
|
||||||
|
for (long masterKeyId : masterKeyIds) {
|
||||||
|
mImportedMasterKeyIds.add(masterKeyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if any key import has been cancelled, set result type to cancelled
|
||||||
|
// resultType is added to in getConsolidatedKayImport to account for remaining factors
|
||||||
|
mResultType |= result.getResult() & ImportKeyResult.RESULT_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns accumulated result of all imports so far
|
||||||
|
*/
|
||||||
|
public ImportKeyResult getConsolidatedResult() {
|
||||||
|
|
||||||
|
// adding required information to mResultType
|
||||||
|
// special case,no keys requested for import
|
||||||
|
if (mBadKeys == 0 && mNewKeys == 0 && mUpdatedKeys == 0) {
|
||||||
|
mResultType = ImportKeyResult.RESULT_FAIL_NOTHING;
|
||||||
|
} else {
|
||||||
|
if (mNewKeys > 0) {
|
||||||
|
mResultType |= ImportKeyResult.RESULT_OK_NEWKEYS;
|
||||||
|
}
|
||||||
|
if (mUpdatedKeys > 0) {
|
||||||
|
mResultType |= ImportKeyResult.RESULT_OK_UPDATED;
|
||||||
|
}
|
||||||
|
if (mBadKeys > 0) {
|
||||||
|
mResultType |= ImportKeyResult.RESULT_WITH_ERRORS;
|
||||||
|
if (mNewKeys == 0 && mUpdatedKeys == 0) {
|
||||||
|
mResultType |= ImportKeyResult.RESULT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mImportLog.containsWarnings()) {
|
||||||
|
mResultType |= ImportKeyResult.RESULT_WARNINGS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long masterKeyIds[] = new long[mImportedMasterKeyIds.size()];
|
||||||
for (int i = 0; i < masterKeyIds.length; i++) {
|
for (int i = 0; i < masterKeyIds.length; i++) {
|
||||||
ids[i] = Long.toString(masterKeyIds[i]);
|
masterKeyIds[i] = mImportedMasterKeyIds.get(i);
|
||||||
if (i != 0) {
|
|
||||||
placeholders.append(",?");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// put together selection string
|
return new ImportKeyResult(mResultType, mImportLog, mNewKeys, mUpdatedKeys, mBadKeys,
|
||||||
selection = Tables.KEY_RINGS_PUBLIC + "." + KeyRings.MASTER_KEY_ID
|
mSecret, masterKeyIds);
|
||||||
+ " IN (" + placeholders + ")";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = mProviderHelper.getContentResolver().query(
|
public boolean isImportFinished() {
|
||||||
KeyRings.buildUnifiedKeyRingsUri(), new String[]{
|
return mTotalKeys == mImportedKeys;
|
||||||
KeyRings.MASTER_KEY_ID, KeyRings.PUBKEY_DATA,
|
|
||||||
KeyRings.PRIVKEY_DATA, KeyRings.HAS_ANY_SECRET
|
|
||||||
}, selection, ids, Tables.KEYS + "." + KeyRings.MASTER_KEY_ID
|
|
||||||
);
|
|
||||||
|
|
||||||
if (cursor == null || !cursor.moveToFirst()) {
|
|
||||||
log.add(LogType.MSG_EXPORT_ERROR_DB, 1);
|
|
||||||
return new ExportResult(ExportResult.RESULT_ERROR, log, okPublic, okSecret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int numKeys = cursor.getCount();
|
|
||||||
|
|
||||||
updateProgress(
|
|
||||||
mContext.getResources().getQuantityString(R.plurals.progress_exporting_key,
|
|
||||||
numKeys), 0, numKeys);
|
|
||||||
|
|
||||||
// For each public masterKey id
|
|
||||||
while (!cursor.isAfterLast()) {
|
|
||||||
|
|
||||||
long keyId = cursor.getLong(0);
|
|
||||||
ArmoredOutputStream arOutStream = null;
|
|
||||||
|
|
||||||
// Create an output stream
|
|
||||||
try {
|
|
||||||
arOutStream = new ArmoredOutputStream(outStream);
|
|
||||||
|
|
||||||
log.add(LogType.MSG_EXPORT_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(keyId));
|
|
||||||
|
|
||||||
byte[] data = cursor.getBlob(1);
|
|
||||||
CanonicalizedKeyRing ring =
|
|
||||||
UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true);
|
|
||||||
ring.encode(arOutStream);
|
|
||||||
|
|
||||||
okPublic += 1;
|
|
||||||
} catch (PgpGeneralException e) {
|
|
||||||
log.add(LogType.MSG_EXPORT_ERROR_KEY, 2);
|
|
||||||
updateProgress(progress++, numKeys);
|
|
||||||
continue;
|
|
||||||
} finally {
|
|
||||||
// make sure this is closed
|
|
||||||
if (arOutStream != null) {
|
|
||||||
arOutStream.close();
|
|
||||||
}
|
|
||||||
arOutStream = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exportSecret && cursor.getInt(3) > 0) {
|
|
||||||
try {
|
|
||||||
arOutStream = new ArmoredOutputStream(outStream);
|
|
||||||
|
|
||||||
// export secret key part
|
|
||||||
log.add(LogType.MSG_EXPORT_SECRET, 2, KeyFormattingUtils.beautifyKeyId(keyId));
|
|
||||||
byte[] data = cursor.getBlob(2);
|
|
||||||
CanonicalizedKeyRing ring =
|
|
||||||
UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true);
|
|
||||||
ring.encode(arOutStream);
|
|
||||||
|
|
||||||
okSecret += 1;
|
|
||||||
} catch (PgpGeneralException e) {
|
|
||||||
log.add(LogType.MSG_EXPORT_ERROR_KEY, 2);
|
|
||||||
updateProgress(progress++, numKeys);
|
|
||||||
continue;
|
|
||||||
} finally {
|
|
||||||
// make sure this is closed
|
|
||||||
if (arOutStream != null) {
|
|
||||||
arOutStream.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateProgress(progress++, numKeys);
|
|
||||||
|
|
||||||
cursor.moveToNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateProgress(R.string.progress_done, numKeys, numKeys);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.add(LogType.MSG_EXPORT_ERROR_IO, 1);
|
|
||||||
return new ExportResult(ExportResult.RESULT_ERROR, log, okPublic, okSecret);
|
|
||||||
} finally {
|
|
||||||
// Make sure the stream is closed
|
|
||||||
if (outStream != null) try {
|
|
||||||
outStream.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(Constants.TAG, "error closing stream", e);
|
|
||||||
}
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
log.add(LogType.MSG_EXPORT_SUCCESS, 1);
|
|
||||||
return new ExportResult(ExportResult.RESULT_OK, log, okPublic, okSecret);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||||
|
* Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.operations;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.textuality.keybase.lib.Proof;
|
||||||
|
import com.textuality.keybase.lib.prover.Prover;
|
||||||
|
import de.measite.minidns.Client;
|
||||||
|
import de.measite.minidns.DNSMessage;
|
||||||
|
import de.measite.minidns.Question;
|
||||||
|
import de.measite.minidns.Record;
|
||||||
|
import de.measite.minidns.record.Data;
|
||||||
|
import de.measite.minidns.record.TXT;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.spongycastle.openpgp.PGPUtil;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.KeybaseVerificationResult;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||||
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificationParcel> {
|
||||||
|
|
||||||
|
public KeybaseVerificationOperation(Context context, ProviderHelper providerHelper,
|
||||||
|
Progressable progressable) {
|
||||||
|
super(context, providerHelper, progressable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeybaseVerificationResult execute(KeybaseVerificationParcel keybaseInput,
|
||||||
|
CryptoInputParcel cryptoInput) {
|
||||||
|
|
||||||
|
String requiredFingerprint = keybaseInput.mRequiredFingerprint;
|
||||||
|
|
||||||
|
OperationResult.OperationLog log = new OperationResult.OperationLog();
|
||||||
|
log.add(OperationResult.LogType.MSG_KEYBASE_VERIFICATION, 0, requiredFingerprint);
|
||||||
|
|
||||||
|
try {
|
||||||
|
String keybaseProof = keybaseInput.mKeybaseProof;
|
||||||
|
Proof proof = new Proof(new JSONObject(keybaseProof));
|
||||||
|
mProgressable.setProgress(R.string.keybase_message_fetching_data, 0, 100);
|
||||||
|
|
||||||
|
Prover prover = Prover.findProverFor(proof);
|
||||||
|
|
||||||
|
if (prover == null) {
|
||||||
|
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_NO_PROVER, 1,
|
||||||
|
proof.getPrettyName());
|
||||||
|
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prover.fetchProofData()) {
|
||||||
|
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_FETCH_PROOF, 1);
|
||||||
|
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prover.checkFingerprint(requiredFingerprint)) {
|
||||||
|
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_FINGERPRINT_MISMATCH, 1);
|
||||||
|
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
String domain = prover.dnsTxtCheckRequired();
|
||||||
|
if (domain != null) {
|
||||||
|
DNSMessage dnsQuery = new Client().query(new Question(domain, Record.TYPE.TXT));
|
||||||
|
if (dnsQuery == null) {
|
||||||
|
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_DNS_FAIL, 1);
|
||||||
|
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 2,
|
||||||
|
getFlattenedProverLog(prover));
|
||||||
|
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
Record[] records = dnsQuery.getAnswers();
|
||||||
|
List<List<byte[]>> extents = new ArrayList<List<byte[]>>();
|
||||||
|
for (Record r : records) {
|
||||||
|
Data d = r.getPayload();
|
||||||
|
if (d instanceof TXT) {
|
||||||
|
extents.add(((TXT) d).getExtents());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!prover.checkDnsTxt(extents)) {
|
||||||
|
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 1,
|
||||||
|
getFlattenedProverLog(prover));
|
||||||
|
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] messageBytes = prover.getPgpMessage().getBytes();
|
||||||
|
if (prover.rawMessageCheckRequired()) {
|
||||||
|
InputStream messageByteStream = PGPUtil.getDecoderStream(new
|
||||||
|
ByteArrayInputStream
|
||||||
|
(messageBytes));
|
||||||
|
if (!prover.checkRawMessageBytes(messageByteStream)) {
|
||||||
|
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 1,
|
||||||
|
getFlattenedProverLog(prover));
|
||||||
|
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PgpDecryptVerify op = new PgpDecryptVerify(mContext, mProviderHelper, mProgressable);
|
||||||
|
|
||||||
|
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(messageBytes)
|
||||||
|
.setSignedLiteralData(true)
|
||||||
|
.setRequiredSignerFingerprint(requiredFingerprint);
|
||||||
|
|
||||||
|
DecryptVerifyResult decryptVerifyResult = op.execute(input, new CryptoInputParcel());
|
||||||
|
|
||||||
|
if (!decryptVerifyResult.success()) {
|
||||||
|
log.add(decryptVerifyResult, 1);
|
||||||
|
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prover.validate(new String(decryptVerifyResult.getOutputBytes()))) {
|
||||||
|
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_PAYLOAD_MISMATCH, 1);
|
||||||
|
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new KeybaseVerificationResult(OperationResult.RESULT_OK, log, prover);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// just adds the passed parameter, in this case e.getMessage()
|
||||||
|
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 1, e.getMessage());
|
||||||
|
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFlattenedProverLog(Prover prover) {
|
||||||
|
String log = "";
|
||||||
|
for (String line : prover.getLog()) {
|
||||||
|
log += line + "\n";
|
||||||
|
}
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,6 +32,8 @@ import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
|||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
||||||
|
import org.sufficientlysecure.keychain.service.PromoteKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
|
|
||||||
@@ -45,13 +47,24 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
* without secret key material, using a GNU_DUMMY s2k type.
|
* without secret key material, using a GNU_DUMMY s2k type.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class PromoteKeyOperation extends BaseOperation {
|
public class PromoteKeyOperation extends BaseOperation<PromoteKeyringParcel> {
|
||||||
|
|
||||||
public PromoteKeyOperation(Context context, ProviderHelper providerHelper,
|
public PromoteKeyOperation(Context context, ProviderHelper providerHelper,
|
||||||
Progressable progressable, AtomicBoolean cancelled) {
|
Progressable progressable, AtomicBoolean cancelled) {
|
||||||
super(context, providerHelper, progressable, cancelled);
|
super(context, providerHelper, progressable, cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PromoteKeyResult execute(PromoteKeyringParcel promoteKeyringParcel,
|
||||||
|
CryptoInputParcel cryptoInputParcel) {
|
||||||
|
// Input
|
||||||
|
long masterKeyId = promoteKeyringParcel.mKeyRingId;
|
||||||
|
byte[] cardAid = promoteKeyringParcel.mCardAid;
|
||||||
|
long[] subKeyIds = promoteKeyringParcel.mSubKeyIds;
|
||||||
|
|
||||||
|
return execute(masterKeyId, cardAid, subKeyIds);
|
||||||
|
}
|
||||||
|
|
||||||
public PromoteKeyResult execute(long masterKeyId, byte[] cardAid, long[] subKeyIds) {
|
public PromoteKeyResult execute(long masterKeyId, byte[] cardAid, long[] subKeyIds) {
|
||||||
|
|
||||||
OperationLog log = new OperationLog();
|
OperationLog log = new OperationLog();
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||||
|
* Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.operations.results;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import com.textuality.keybase.lib.KeybaseException;
|
||||||
|
import com.textuality.keybase.lib.prover.Prover;
|
||||||
|
|
||||||
|
public class KeybaseVerificationResult extends OperationResult implements Parcelable {
|
||||||
|
public final String mProofUrl;
|
||||||
|
public final String mPresenceUrl;
|
||||||
|
public final String mPresenceLabel;
|
||||||
|
|
||||||
|
public KeybaseVerificationResult(int result, OperationLog log) {
|
||||||
|
super(result, log);
|
||||||
|
mProofUrl = null;
|
||||||
|
mPresenceLabel = null;
|
||||||
|
mPresenceUrl = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeybaseVerificationResult(int result, OperationLog log, Prover prover)
|
||||||
|
throws KeybaseException {
|
||||||
|
super(result, log);
|
||||||
|
mProofUrl = prover.getProofUrl();
|
||||||
|
mPresenceUrl = prover.getPresenceUrl();
|
||||||
|
mPresenceLabel = prover.getPresenceLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KeybaseVerificationResult(Parcel in) {
|
||||||
|
super(in);
|
||||||
|
mProofUrl = in.readString();
|
||||||
|
mPresenceUrl = in.readString();
|
||||||
|
mPresenceLabel = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
super.writeToParcel(dest, flags);
|
||||||
|
dest.writeString(mProofUrl);
|
||||||
|
dest.writeString(mPresenceUrl);
|
||||||
|
dest.writeString(mPresenceLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<KeybaseVerificationResult> CREATOR = new Parcelable.Creator<KeybaseVerificationResult>() {
|
||||||
|
@Override
|
||||||
|
public KeybaseVerificationResult createFromParcel(Parcel in) {
|
||||||
|
return new KeybaseVerificationResult(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeybaseVerificationResult[] newArray(int size) {
|
||||||
|
return new KeybaseVerificationResult[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -750,7 +750,19 @@ public abstract class OperationResult implements Parcelable {
|
|||||||
MSG_DEL_OK (LogLevel.OK, R.plurals.msg_del_ok),
|
MSG_DEL_OK (LogLevel.OK, R.plurals.msg_del_ok),
|
||||||
MSG_DEL_FAIL (LogLevel.WARN, R.plurals.msg_del_fail),
|
MSG_DEL_FAIL (LogLevel.WARN, R.plurals.msg_del_fail),
|
||||||
|
|
||||||
//export log
|
// keybase verification
|
||||||
|
MSG_KEYBASE_VERIFICATION(LogLevel.START, R.string.msg_keybase_verification),
|
||||||
|
|
||||||
|
MSG_KEYBASE_ERROR_NO_PROVER(LogLevel.ERROR, R.string.msg_keybase_error_no_prover),
|
||||||
|
MSG_KEYBASE_ERROR_FETCH_PROOF(LogLevel.ERROR, R.string.msg_keybase_error_fetching_evidence),
|
||||||
|
MSG_KEYBASE_ERROR_FINGERPRINT_MISMATCH(LogLevel.ERROR,
|
||||||
|
R.string.msg_keybase_error_key_mismatch),
|
||||||
|
MSG_KEYBASE_ERROR_DNS_FAIL(LogLevel.ERROR, R.string.msg_keybase_error_dns_fail),
|
||||||
|
MSG_KEYBASE_ERROR_SPECIFIC(LogLevel.ERROR, R.string.msg_keybase_error_specific),
|
||||||
|
MSG_KEYBASE_ERROR_PAYLOAD_MISMATCH(LogLevel.ERROR,
|
||||||
|
R.string.msg_keybase_error_msg_payload_mismatch),
|
||||||
|
|
||||||
|
// export log
|
||||||
MSG_EXPORT_LOG(LogLevel.START,R.string.msg_export_log_start),
|
MSG_EXPORT_LOG(LogLevel.START,R.string.msg_export_log_start),
|
||||||
MSG_EXPORT_LOG_EXPORT_ERROR_NO_FILE(LogLevel.ERROR,R.string.msg_export_log_error_no_file),
|
MSG_EXPORT_LOG_EXPORT_ERROR_NO_FILE(LogLevel.ERROR,R.string.msg_export_log_error_no_file),
|
||||||
MSG_EXPORT_LOG_EXPORT_ERROR_FOPEN(LogLevel.ERROR,R.string.msg_export_log_error_fopen),
|
MSG_EXPORT_LOG_EXPORT_ERROR_FOPEN(LogLevel.ERROR,R.string.msg_export_log_error_fopen),
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import org.spongycastle.bcpg.CompressionAlgorithmTags;
|
|||||||
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.ImportExportOperation;
|
import org.sufficientlysecure.keychain.operations.ImportOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
|
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||||
@@ -1248,9 +1248,9 @@ public class ProviderHelper {
|
|||||||
// 3. Re-Import secret keyrings from cache
|
// 3. Re-Import secret keyrings from cache
|
||||||
if (numSecrets > 0) {
|
if (numSecrets > 0) {
|
||||||
|
|
||||||
ImportKeyResult result = new ImportExportOperation(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))
|
||||||
.importKeyRings(itSecrets, numSecrets, null);
|
.serialKeyRingImport(itSecrets, numSecrets, null);
|
||||||
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);
|
||||||
@@ -1276,9 +1276,9 @@ public class ProviderHelper {
|
|||||||
// 4. Re-Import public keyrings from cache
|
// 4. Re-Import public keyrings from cache
|
||||||
if (numPublics > 0) {
|
if (numPublics > 0) {
|
||||||
|
|
||||||
ImportKeyResult result = new ImportExportOperation(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))
|
||||||
.importKeyRings(itPublics, numPublics, null);
|
.serialKeyRingImport(itPublics, numPublics, null);
|
||||||
log.add(result, indent);
|
log.add(result, indent);
|
||||||
} else {
|
} else {
|
||||||
log.add(LogType.MSG_CON_REIMPORT_PUBLIC_SKIP, indent);
|
log.add(LogType.MSG_CON_REIMPORT_PUBLIC_SKIP, indent);
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||||
|
* Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.service;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
public class ConsolidateInputParcel implements Parcelable {
|
||||||
|
|
||||||
|
public boolean mConsolidateRecovery;
|
||||||
|
|
||||||
|
public ConsolidateInputParcel(boolean consolidateRecovery) {
|
||||||
|
mConsolidateRecovery = consolidateRecovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ConsolidateInputParcel(Parcel in) {
|
||||||
|
mConsolidateRecovery = in.readByte() != 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeByte((byte) (mConsolidateRecovery ? 0x01 : 0x00));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<ConsolidateInputParcel> CREATOR = new Parcelable.Creator<ConsolidateInputParcel>() {
|
||||||
|
@Override
|
||||||
|
public ConsolidateInputParcel createFromParcel(Parcel in) {
|
||||||
|
return new ConsolidateInputParcel(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConsolidateInputParcel[] newArray(int size) {
|
||||||
|
return new ConsolidateInputParcel[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||||
|
* Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.service;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
public class DeleteKeyringParcel implements Parcelable {
|
||||||
|
|
||||||
|
public long[] mMasterKeyIds;
|
||||||
|
public boolean mIsSecret;
|
||||||
|
|
||||||
|
public DeleteKeyringParcel(long[] masterKeyIds, boolean isSecret) {
|
||||||
|
mMasterKeyIds = masterKeyIds;
|
||||||
|
mIsSecret = isSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DeleteKeyringParcel(Parcel in) {
|
||||||
|
mIsSecret = in.readByte() != 0x00;
|
||||||
|
mMasterKeyIds = in.createLongArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeByte((byte) (mIsSecret ? 0x01 : 0x00));
|
||||||
|
dest.writeLongArray(mMasterKeyIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<DeleteKeyringParcel> CREATOR = new Parcelable.Creator<DeleteKeyringParcel>() {
|
||||||
|
@Override
|
||||||
|
public DeleteKeyringParcel createFromParcel(Parcel in) {
|
||||||
|
return new DeleteKeyringParcel(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeleteKeyringParcel[] newArray(int size) {
|
||||||
|
return new DeleteKeyringParcel[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||||
|
* Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.service;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
public class ExportKeyringParcel implements Parcelable {
|
||||||
|
public String mKeyserver;
|
||||||
|
public Uri mCanonicalizedPublicKeyringUri;
|
||||||
|
|
||||||
|
public boolean mExportSecret;
|
||||||
|
public long mMasterKeyIds[];
|
||||||
|
public String mOutputFile;
|
||||||
|
public Uri mOutputUri;
|
||||||
|
public ExportType mExportType;
|
||||||
|
|
||||||
|
public enum ExportType {
|
||||||
|
UPLOAD_KEYSERVER,
|
||||||
|
EXPORT_FILE,
|
||||||
|
EXPORT_URI
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportKeyringParcel(String keyserver, Uri keyringUri) {
|
||||||
|
mExportType = ExportType.UPLOAD_KEYSERVER;
|
||||||
|
mKeyserver = keyserver;
|
||||||
|
mCanonicalizedPublicKeyringUri = keyringUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportKeyringParcel(long[] masterKeyIds, boolean exportSecret, String outputFile) {
|
||||||
|
mExportType = ExportType.EXPORT_FILE;
|
||||||
|
mMasterKeyIds = masterKeyIds;
|
||||||
|
mExportSecret = exportSecret;
|
||||||
|
mOutputFile = outputFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportKeyringParcel(long[] masterKeyIds, boolean exportSecret, Uri outputUri) {
|
||||||
|
mExportType = ExportType.EXPORT_URI;
|
||||||
|
mMasterKeyIds = masterKeyIds;
|
||||||
|
mExportSecret = exportSecret;
|
||||||
|
mOutputUri = outputUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ExportKeyringParcel(Parcel in) {
|
||||||
|
mKeyserver = in.readString();
|
||||||
|
mCanonicalizedPublicKeyringUri = (Uri) in.readValue(Uri.class.getClassLoader());
|
||||||
|
mExportSecret = in.readByte() != 0x00;
|
||||||
|
mOutputFile = in.readString();
|
||||||
|
mOutputUri = (Uri) in.readValue(Uri.class.getClassLoader());
|
||||||
|
mExportType = (ExportType) in.readValue(ExportType.class.getClassLoader());
|
||||||
|
mMasterKeyIds = in.createLongArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(mKeyserver);
|
||||||
|
dest.writeValue(mCanonicalizedPublicKeyringUri);
|
||||||
|
dest.writeByte((byte) (mExportSecret ? 0x01 : 0x00));
|
||||||
|
dest.writeString(mOutputFile);
|
||||||
|
dest.writeValue(mOutputUri);
|
||||||
|
dest.writeValue(mExportType);
|
||||||
|
dest.writeLongArray(mMasterKeyIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<ExportKeyringParcel> CREATOR = new Parcelable.Creator<ExportKeyringParcel>() {
|
||||||
|
@Override
|
||||||
|
public ExportKeyringParcel createFromParcel(Parcel in) {
|
||||||
|
return new ExportKeyringParcel(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExportKeyringParcel[] newArray(int size) {
|
||||||
|
return new ExportKeyringParcel[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.service;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class ImportKeyringParcel implements Parcelable {
|
||||||
|
// if null, keys are expected to be read from a cache file in ImportExportOperations
|
||||||
|
public ArrayList<ParcelableKeyRing> mKeyList;
|
||||||
|
public String mKeyserver; // must be set if keys are to be imported from a keyserver
|
||||||
|
|
||||||
|
public ImportKeyringParcel (ArrayList<ParcelableKeyRing> keyList, String keyserver) {
|
||||||
|
mKeyList = keyList;
|
||||||
|
mKeyserver = keyserver;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ImportKeyringParcel(Parcel in) {
|
||||||
|
if (in.readByte() == 0x01) {
|
||||||
|
mKeyList = new ArrayList<>();
|
||||||
|
in.readList(mKeyList, ParcelableKeyRing.class.getClassLoader());
|
||||||
|
} else {
|
||||||
|
mKeyList = null;
|
||||||
|
}
|
||||||
|
mKeyserver = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
if (mKeyList == null) {
|
||||||
|
dest.writeByte((byte) (0x00));
|
||||||
|
} else {
|
||||||
|
dest.writeByte((byte) (0x01));
|
||||||
|
dest.writeList(mKeyList);
|
||||||
|
}
|
||||||
|
dest.writeString(mKeyserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<ImportKeyringParcel> CREATOR = new Parcelable.Creator<ImportKeyringParcel>() {
|
||||||
|
@Override
|
||||||
|
public ImportKeyringParcel createFromParcel(Parcel in) {
|
||||||
|
return new ImportKeyringParcel(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImportKeyringParcel[] newArray(int size) {
|
||||||
|
return new ImportKeyringParcel[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||||
|
* Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.service;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
public class KeybaseVerificationParcel implements Parcelable {
|
||||||
|
|
||||||
|
public String mKeybaseProof;
|
||||||
|
public String mRequiredFingerprint;
|
||||||
|
|
||||||
|
public KeybaseVerificationParcel(String keybaseProof, String requiredFingerprint) {
|
||||||
|
mKeybaseProof = keybaseProof;
|
||||||
|
mRequiredFingerprint = requiredFingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KeybaseVerificationParcel(Parcel in) {
|
||||||
|
mKeybaseProof = in.readString();
|
||||||
|
mRequiredFingerprint = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(mKeybaseProof);
|
||||||
|
dest.writeString(mRequiredFingerprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<KeybaseVerificationParcel> CREATOR = new Parcelable.Creator<KeybaseVerificationParcel>() {
|
||||||
|
@Override
|
||||||
|
public KeybaseVerificationParcel createFromParcel(Parcel in) {
|
||||||
|
return new KeybaseVerificationParcel(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeybaseVerificationParcel[] newArray(int size) {
|
||||||
|
return new KeybaseVerificationParcel[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.sufficientlysecure.keychain.service;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
import android.app.Service;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
|
||||||
import org.sufficientlysecure.keychain.operations.BaseOperation;
|
|
||||||
import org.sufficientlysecure.keychain.operations.CertifyOperation;
|
|
||||||
import org.sufficientlysecure.keychain.operations.EditKeyOperation;
|
|
||||||
import org.sufficientlysecure.keychain.operations.SignEncryptOperation;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
|
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
|
||||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
|
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
|
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This Service contains all important long lasting operations for OpenKeychain. It receives Intents with
|
|
||||||
* data from the activities or other apps, executes them, and stops itself after doing them.
|
|
||||||
*/
|
|
||||||
public class KeychainNewService extends Service implements Progressable {
|
|
||||||
|
|
||||||
// messenger for communication (hack)
|
|
||||||
public static final String EXTRA_MESSENGER = "messenger";
|
|
||||||
|
|
||||||
// extras for operation
|
|
||||||
public static final String EXTRA_OPERATION_INPUT = "op_input";
|
|
||||||
public static final String EXTRA_CRYPTO_INPUT = "crypto_input";
|
|
||||||
|
|
||||||
// this attribute can possibly merged with the one above? not sure...
|
|
||||||
private AtomicBoolean mActionCanceled = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
ThreadLocal<Messenger> mMessenger = new ThreadLocal<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBinder onBind(Intent intent) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is run on the main thread, we need to spawn a runnable which runs on another thread for the actual operation
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int onStartCommand(final Intent intent, int flags, int startId) {
|
|
||||||
|
|
||||||
Runnable actionRunnable = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// We have not been cancelled! (yet)
|
|
||||||
mActionCanceled.set(false);
|
|
||||||
|
|
||||||
Bundle extras = intent.getExtras();
|
|
||||||
|
|
||||||
// Set messenger for communication (for this particular thread)
|
|
||||||
mMessenger.set(extras.<Messenger>getParcelable(EXTRA_MESSENGER));
|
|
||||||
|
|
||||||
// Input
|
|
||||||
Parcelable inputParcel = extras.getParcelable(EXTRA_OPERATION_INPUT);
|
|
||||||
CryptoInputParcel cryptoInput = extras.getParcelable(EXTRA_CRYPTO_INPUT);
|
|
||||||
|
|
||||||
// Operation
|
|
||||||
BaseOperation op;
|
|
||||||
|
|
||||||
// just for brevity
|
|
||||||
KeychainNewService outerThis = KeychainNewService.this;
|
|
||||||
if (inputParcel instanceof SignEncryptParcel) {
|
|
||||||
op = new SignEncryptOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
|
|
||||||
} else if (inputParcel instanceof PgpDecryptVerifyInputParcel) {
|
|
||||||
op = new PgpDecryptVerify(outerThis, new ProviderHelper(outerThis), outerThis);
|
|
||||||
} else if (inputParcel instanceof SaveKeyringParcel) {
|
|
||||||
op = new EditKeyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
|
|
||||||
} else if (inputParcel instanceof CertifyAction) {
|
|
||||||
op = new CertifyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") // this is unchecked, we make sure it's the correct op above!
|
|
||||||
OperationResult result = op.execute(inputParcel, cryptoInput);
|
|
||||||
|
|
||||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Thread actionThread = new Thread(actionRunnable);
|
|
||||||
actionThread.start();
|
|
||||||
|
|
||||||
return START_NOT_STICKY;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendMessageToHandler(MessageStatus status, Integer arg2, Bundle data) {
|
|
||||||
|
|
||||||
Message msg = Message.obtain();
|
|
||||||
assert msg != null;
|
|
||||||
msg.arg1 = status.ordinal();
|
|
||||||
if (arg2 != null) {
|
|
||||||
msg.arg2 = arg2;
|
|
||||||
}
|
|
||||||
if (data != null) {
|
|
||||||
msg.setData(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
mMessenger.get().send(msg);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
Log.w(Constants.TAG, "Messenger is null!", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendMessageToHandler(MessageStatus status, OperationResult data) {
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putParcelable(OperationResult.EXTRA_RESULT, data);
|
|
||||||
sendMessageToHandler(status, null, bundle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendMessageToHandler(MessageStatus status) {
|
|
||||||
sendMessageToHandler(status, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set progress of ProgressDialog by sending message to handler on UI thread
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setProgress(String message, int progress, int max) {
|
|
||||||
Log.d(Constants.TAG, "Send message by setProgress with progress=" + progress + ", max="
|
|
||||||
+ max);
|
|
||||||
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
if (message != null) {
|
|
||||||
data.putString(ServiceProgressHandler.DATA_MESSAGE, message);
|
|
||||||
}
|
|
||||||
data.putInt(ServiceProgressHandler.DATA_PROGRESS, progress);
|
|
||||||
data.putInt(ServiceProgressHandler.DATA_PROGRESS_MAX, max);
|
|
||||||
|
|
||||||
sendMessageToHandler(MessageStatus.UPDATE_PROGRESS, null, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setProgress(int resourceId, int progress, int max) {
|
|
||||||
setProgress(getString(resourceId), progress, max);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setProgress(int progress, int max) {
|
|
||||||
setProgress(null, progress, max);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPreventCancel() {
|
|
||||||
sendMessageToHandler(MessageStatus.PREVENT_CANCEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -20,146 +20,55 @@ package org.sufficientlysecure.keychain.service;
|
|||||||
|
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
|
||||||
import com.textuality.keybase.lib.Proof;
|
|
||||||
import com.textuality.keybase.lib.prover.Prover;
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.spongycastle.openpgp.PGPUtil;
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.operations.BaseOperation;
|
||||||
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
|
|
||||||
import org.sufficientlysecure.keychain.keyimport.Keyserver;
|
|
||||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
|
||||||
import org.sufficientlysecure.keychain.operations.CertifyOperation;
|
import org.sufficientlysecure.keychain.operations.CertifyOperation;
|
||||||
|
import org.sufficientlysecure.keychain.operations.ConsolidateOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.DeleteOperation;
|
import org.sufficientlysecure.keychain.operations.DeleteOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.EditKeyOperation;
|
import org.sufficientlysecure.keychain.operations.EditKeyOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.ImportExportOperation;
|
import org.sufficientlysecure.keychain.operations.ExportOperation;
|
||||||
|
import org.sufficientlysecure.keychain.operations.ImportOperation;
|
||||||
|
import org.sufficientlysecure.keychain.operations.KeybaseVerificationOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.PromoteKeyOperation;
|
import org.sufficientlysecure.keychain.operations.PromoteKeyOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.SignEncryptOperation;
|
import org.sufficientlysecure.keychain.operations.SignEncryptOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
|
||||||
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.operations.results.OperationResult.OperationLog;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
||||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||||
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
|
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
|
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
|
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
|
||||||
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.SynchronousQueue;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import de.measite.minidns.Client;
|
|
||||||
import de.measite.minidns.DNSMessage;
|
|
||||||
import de.measite.minidns.Question;
|
|
||||||
import de.measite.minidns.Record;
|
|
||||||
import de.measite.minidns.record.Data;
|
|
||||||
import de.measite.minidns.record.TXT;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Service contains all important long lasting operations for OpenKeychain. It receives Intents with
|
* This Service contains all important long lasting operations for OpenKeychain. It receives Intents with
|
||||||
* data from the activities or other apps, executes them, and stops itself after doing them.
|
* data from the activities or other apps, executes them, and stops itself after doing them.
|
||||||
*/
|
*/
|
||||||
public class KeychainService extends Service implements Progressable {
|
public class KeychainService extends Service implements Progressable {
|
||||||
|
|
||||||
/* extras that can be given by intent */
|
// messenger for communication (hack)
|
||||||
public static final String EXTRA_MESSENGER = "messenger";
|
public static final String EXTRA_MESSENGER = "messenger";
|
||||||
public static final String EXTRA_DATA = "data";
|
|
||||||
|
|
||||||
/* possible actions */
|
// extras for operation
|
||||||
|
public static final String EXTRA_OPERATION_INPUT = "op_input";
|
||||||
public static final String ACTION_VERIFY_KEYBASE_PROOF = Constants.INTENT_PREFIX + "VERIFY_KEYBASE_PROOF";
|
|
||||||
|
|
||||||
public static final String ACTION_EDIT_KEYRING = Constants.INTENT_PREFIX + "EDIT_KEYRING";
|
|
||||||
|
|
||||||
public static final String ACTION_PROMOTE_KEYRING = Constants.INTENT_PREFIX + "PROMOTE_KEYRING";
|
|
||||||
|
|
||||||
public static final String ACTION_IMPORT_KEYRING = Constants.INTENT_PREFIX + "IMPORT_KEYRING";
|
|
||||||
public static final String ACTION_EXPORT_KEYRING = Constants.INTENT_PREFIX + "EXPORT_KEYRING";
|
|
||||||
|
|
||||||
public static final String ACTION_UPLOAD_KEYRING = Constants.INTENT_PREFIX + "UPLOAD_KEYRING";
|
|
||||||
|
|
||||||
public static final String ACTION_DELETE = Constants.INTENT_PREFIX + "DELETE";
|
|
||||||
|
|
||||||
public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE";
|
|
||||||
|
|
||||||
public static final String ACTION_CANCEL = Constants.INTENT_PREFIX + "CANCEL";
|
|
||||||
|
|
||||||
/* keys for data bundle */
|
|
||||||
|
|
||||||
// keybase proof
|
|
||||||
public static final String KEYBASE_REQUIRED_FINGERPRINT = "keybase_required_fingerprint";
|
|
||||||
public static final String KEYBASE_PROOF = "keybase_proof";
|
|
||||||
|
|
||||||
// save keyring
|
|
||||||
public static final String EDIT_KEYRING_PARCEL = "save_parcel";
|
|
||||||
public static final String EDIT_KEYRING_PASSPHRASE = "passphrase";
|
|
||||||
public static final String EXTRA_CRYPTO_INPUT = "crypto_input";
|
public static final String EXTRA_CRYPTO_INPUT = "crypto_input";
|
||||||
|
|
||||||
// delete keyring(s)
|
public static final String ACTION_CANCEL = "action_cancel";
|
||||||
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_SERVER = "import_key_server";
|
|
||||||
|
|
||||||
// export key
|
|
||||||
public static final String EXPORT_FILENAME = "export_filename";
|
|
||||||
public static final String EXPORT_URI = "export_uri";
|
|
||||||
public static final String EXPORT_SECRET = "export_secret";
|
|
||||||
public static final String EXPORT_ALL = "export_all";
|
|
||||||
public static final String EXPORT_KEY_RING_MASTER_KEY_ID = "export_key_ring_id";
|
|
||||||
|
|
||||||
// upload key
|
|
||||||
public static final String UPLOAD_KEY_SERVER = "upload_key_server";
|
|
||||||
|
|
||||||
// promote key
|
|
||||||
public static final String PROMOTE_MASTER_KEY_ID = "promote_master_key_id";
|
|
||||||
public static final String PROMOTE_CARD_AID = "promote_card_aid";
|
|
||||||
public static final String PROMOTE_SUBKEY_IDS = "promote_fingerprints";
|
|
||||||
|
|
||||||
// consolidate
|
|
||||||
public static final String CONSOLIDATE_RECOVERY = "consolidate_recovery";
|
|
||||||
|
|
||||||
Messenger mMessenger;
|
|
||||||
|
|
||||||
// this attribute can possibly merged with the one above? not sure...
|
// this attribute can possibly merged with the one above? not sure...
|
||||||
private AtomicBoolean mActionCanceled = new AtomicBoolean(false);
|
private AtomicBoolean mActionCanceled = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
ThreadLocal<Messenger> mMessenger = new ThreadLocal<>();
|
||||||
private KeyImportAccumulator mKeyImportAccumulator;
|
|
||||||
|
|
||||||
private KeychainService mKeychainService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
@@ -171,9 +80,8 @@ public class KeychainService extends Service implements Progressable {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(final Intent intent, int flags, int startId) {
|
public int onStartCommand(final Intent intent, int flags, int startId) {
|
||||||
mKeychainService = this;
|
|
||||||
|
|
||||||
if (ACTION_CANCEL.equals(intent.getAction())) {
|
if (intent.getAction() != null && intent.getAction().equals(ACTION_CANCEL)) {
|
||||||
mActionCanceled.set(true);
|
mActionCanceled.set(true);
|
||||||
return START_NOT_STICKY;
|
return START_NOT_STICKY;
|
||||||
}
|
}
|
||||||
@@ -185,275 +93,55 @@ public class KeychainService extends Service implements Progressable {
|
|||||||
mActionCanceled.set(false);
|
mActionCanceled.set(false);
|
||||||
|
|
||||||
Bundle extras = intent.getExtras();
|
Bundle extras = intent.getExtras();
|
||||||
if (extras == null) {
|
|
||||||
Log.e(Constants.TAG, "Extras bundle is null!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(extras.containsKey(EXTRA_MESSENGER) || extras.containsKey(EXTRA_DATA) || (intent
|
// Set messenger for communication (for this particular thread)
|
||||||
.getAction() == null))) {
|
mMessenger.set(extras.<Messenger>getParcelable(EXTRA_MESSENGER));
|
||||||
Log.e(Constants.TAG,
|
|
||||||
"Extra bundle must contain a messenger, a data bundle, and an action!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri dataUri = intent.getData();
|
|
||||||
|
|
||||||
mMessenger = (Messenger) extras.get(EXTRA_MESSENGER);
|
|
||||||
Bundle data = extras.getBundle(EXTRA_DATA);
|
|
||||||
if (data == null) {
|
|
||||||
Log.e(Constants.TAG, "data extra is null!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.logDebugBundle(data, "EXTRA_DATA");
|
|
||||||
|
|
||||||
ProviderHelper providerHelper = new ProviderHelper(mKeychainService);
|
|
||||||
|
|
||||||
String action = intent.getAction();
|
|
||||||
|
|
||||||
// executeServiceMethod action from extra bundle
|
|
||||||
switch (action) {
|
|
||||||
case ACTION_CONSOLIDATE: {
|
|
||||||
|
|
||||||
// Operation
|
|
||||||
ConsolidateResult result;
|
|
||||||
if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) {
|
|
||||||
result = providerHelper.consolidateDatabaseStep2(mKeychainService);
|
|
||||||
} else {
|
|
||||||
result = providerHelper.consolidateDatabaseStep1(mKeychainService);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Result
|
|
||||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ACTION_VERIFY_KEYBASE_PROOF: {
|
|
||||||
|
|
||||||
try {
|
|
||||||
Proof proof = new Proof(new JSONObject(data.getString(KEYBASE_PROOF)));
|
|
||||||
setProgress(R.string.keybase_message_fetching_data, 0, 100);
|
|
||||||
|
|
||||||
Prover prover = Prover.findProverFor(proof);
|
|
||||||
|
|
||||||
if (prover == null) {
|
|
||||||
sendProofError(getString(R.string.keybase_no_prover_found) + ": " + proof
|
|
||||||
.getPrettyName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!prover.fetchProofData()) {
|
|
||||||
sendProofError(prover.getLog(), getString(R.string.keybase_problem_fetching_evidence));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String requiredFingerprint = data.getString(KEYBASE_REQUIRED_FINGERPRINT);
|
|
||||||
if (!prover.checkFingerprint(requiredFingerprint)) {
|
|
||||||
sendProofError(getString(R.string.keybase_key_mismatch));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String domain = prover.dnsTxtCheckRequired();
|
|
||||||
if (domain != null) {
|
|
||||||
DNSMessage dnsQuery = new Client().query(new Question(domain, Record.TYPE.TXT));
|
|
||||||
if (dnsQuery == null) {
|
|
||||||
sendProofError(prover.getLog(), getString(R.string.keybase_dns_query_failure));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Record[] records = dnsQuery.getAnswers();
|
|
||||||
List<List<byte[]>> extents = new ArrayList<List<byte[]>>();
|
|
||||||
for (Record r : records) {
|
|
||||||
Data d = r.getPayload();
|
|
||||||
if (d instanceof TXT) {
|
|
||||||
extents.add(((TXT) d).getExtents());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!prover.checkDnsTxt(extents)) {
|
|
||||||
sendProofError(prover.getLog(), null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] messageBytes = prover.getPgpMessage().getBytes();
|
|
||||||
if (prover.rawMessageCheckRequired()) {
|
|
||||||
InputStream messageByteStream = PGPUtil.getDecoderStream(new ByteArrayInputStream
|
|
||||||
(messageBytes));
|
|
||||||
if (!prover.checkRawMessageBytes(messageByteStream)) {
|
|
||||||
sendProofError(prover.getLog(), null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PgpDecryptVerify op = new PgpDecryptVerify(mKeychainService, providerHelper,
|
|
||||||
mKeychainService);
|
|
||||||
|
|
||||||
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(messageBytes)
|
|
||||||
.setSignedLiteralData(true)
|
|
||||||
.setRequiredSignerFingerprint(requiredFingerprint);
|
|
||||||
|
|
||||||
DecryptVerifyResult decryptVerifyResult = op.execute(input, new CryptoInputParcel());
|
|
||||||
|
|
||||||
if (!decryptVerifyResult.success()) {
|
|
||||||
OperationLog log = decryptVerifyResult.getLog();
|
|
||||||
OperationResult.LogEntryParcel lastEntry = null;
|
|
||||||
for (OperationResult.LogEntryParcel entry : log) {
|
|
||||||
lastEntry = entry;
|
|
||||||
}
|
|
||||||
sendProofError(getString(lastEntry.mType.getMsgId()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!prover.validate(new String(decryptVerifyResult.getOutputBytes()))) {
|
|
||||||
sendProofError(getString(R.string.keybase_message_payload_mismatch));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bundle resultData = new Bundle();
|
|
||||||
resultData.putString(ServiceProgressHandler.DATA_MESSAGE, "OK");
|
|
||||||
|
|
||||||
// these help the handler construct a useful human-readable message
|
|
||||||
resultData.putString(ServiceProgressHandler.KEYBASE_PROOF_URL, prover.getProofUrl());
|
|
||||||
resultData.putString(ServiceProgressHandler.KEYBASE_PRESENCE_URL, prover.getPresenceUrl());
|
|
||||||
resultData.putString(ServiceProgressHandler.KEYBASE_PRESENCE_LABEL, prover
|
|
||||||
.getPresenceLabel());
|
|
||||||
sendMessageToHandler(MessageStatus.OKAY, resultData);
|
|
||||||
} catch (Exception e) {
|
|
||||||
sendErrorToHandler(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ACTION_DELETE: {
|
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST);
|
Parcelable inputParcel = extras.getParcelable(EXTRA_OPERATION_INPUT);
|
||||||
boolean isSecret = data.getBoolean(DELETE_IS_SECRET);
|
CryptoInputParcel cryptoInput = extras.getParcelable(EXTRA_CRYPTO_INPUT);
|
||||||
|
|
||||||
// Operation
|
// Operation
|
||||||
DeleteOperation op = new DeleteOperation(mKeychainService, providerHelper, mKeychainService);
|
BaseOperation op;
|
||||||
DeleteResult result = op.execute(masterKeyIds, isSecret);
|
|
||||||
|
|
||||||
// Result
|
// just for brevity
|
||||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
KeychainService outerThis = KeychainService.this;
|
||||||
|
if (inputParcel instanceof SignEncryptParcel) {
|
||||||
break;
|
op = new SignEncryptOperation(outerThis, new ProviderHelper(outerThis),
|
||||||
}
|
outerThis, mActionCanceled);
|
||||||
case ACTION_EDIT_KEYRING: {
|
} else if (inputParcel instanceof PgpDecryptVerifyInputParcel) {
|
||||||
|
op = new PgpDecryptVerify(outerThis, new ProviderHelper(outerThis), outerThis);
|
||||||
// Input
|
} else if (inputParcel instanceof SaveKeyringParcel) {
|
||||||
SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL);
|
op = new EditKeyOperation(outerThis, new ProviderHelper(outerThis), outerThis,
|
||||||
CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
|
|
||||||
|
|
||||||
// Operation
|
|
||||||
EditKeyOperation op = new EditKeyOperation(mKeychainService, providerHelper,
|
|
||||||
mKeychainService, mActionCanceled);
|
|
||||||
OperationResult result = op.execute(saveParcel, cryptoInput);
|
|
||||||
|
|
||||||
// Result
|
|
||||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ACTION_PROMOTE_KEYRING: {
|
|
||||||
|
|
||||||
// Input
|
|
||||||
long keyRingId = data.getLong(PROMOTE_MASTER_KEY_ID);
|
|
||||||
byte[] cardAid = data.getByteArray(PROMOTE_CARD_AID);
|
|
||||||
long[] subKeyIds = data.getLongArray(PROMOTE_SUBKEY_IDS);
|
|
||||||
|
|
||||||
// Operation
|
|
||||||
PromoteKeyOperation op = new PromoteKeyOperation(
|
|
||||||
mKeychainService, providerHelper, mKeychainService,
|
|
||||||
mActionCanceled);
|
mActionCanceled);
|
||||||
PromoteKeyResult result = op.execute(keyRingId, cardAid, subKeyIds);
|
} else if (inputParcel instanceof CertifyActionsParcel) {
|
||||||
|
op = new CertifyOperation(outerThis, new ProviderHelper(outerThis), outerThis,
|
||||||
|
mActionCanceled);
|
||||||
|
} else if (inputParcel instanceof DeleteKeyringParcel) {
|
||||||
|
op = new DeleteOperation(outerThis, new ProviderHelper(outerThis), outerThis);
|
||||||
|
} else if (inputParcel instanceof PromoteKeyringParcel) {
|
||||||
|
op = new PromoteKeyOperation(outerThis, new ProviderHelper(outerThis),
|
||||||
|
outerThis, mActionCanceled);
|
||||||
|
} else if (inputParcel instanceof ImportKeyringParcel) {
|
||||||
|
op = new ImportOperation(outerThis, new ProviderHelper(outerThis), outerThis,
|
||||||
|
mActionCanceled);
|
||||||
|
} else if (inputParcel instanceof ExportKeyringParcel) {
|
||||||
|
op = new ExportOperation(outerThis, new ProviderHelper(outerThis), outerThis,
|
||||||
|
mActionCanceled);
|
||||||
|
} else if (inputParcel instanceof ConsolidateInputParcel) {
|
||||||
|
op = new ConsolidateOperation(outerThis, new ProviderHelper(outerThis),
|
||||||
|
outerThis);
|
||||||
|
} else if (inputParcel instanceof KeybaseVerificationParcel) {
|
||||||
|
op = new KeybaseVerificationOperation(outerThis, new ProviderHelper(outerThis),
|
||||||
|
outerThis);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Result
|
@SuppressWarnings("unchecked") // this is unchecked, we make sure it's the correct op above!
|
||||||
|
OperationResult result = op.execute(inputParcel, cryptoInput);
|
||||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
sendMessageToHandler(MessageStatus.OKAY, result);
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ACTION_EXPORT_KEYRING: {
|
|
||||||
|
|
||||||
// Input
|
|
||||||
boolean exportSecret = data.getBoolean(EXPORT_SECRET, false);
|
|
||||||
String outputFile = data.getString(EXPORT_FILENAME);
|
|
||||||
Uri outputUri = data.getParcelable(EXPORT_URI);
|
|
||||||
|
|
||||||
boolean exportAll = data.getBoolean(EXPORT_ALL);
|
|
||||||
long[] masterKeyIds = exportAll ? null : data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
|
|
||||||
|
|
||||||
// Operation
|
|
||||||
ImportExportOperation importExportOperation = new ImportExportOperation(
|
|
||||||
mKeychainService, providerHelper, mKeychainService);
|
|
||||||
ExportResult result;
|
|
||||||
if (outputFile != null) {
|
|
||||||
result = importExportOperation.exportToFile(masterKeyIds, exportSecret, outputFile);
|
|
||||||
} else {
|
|
||||||
result = importExportOperation.exportToUri(masterKeyIds, exportSecret, outputUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Result
|
|
||||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ACTION_IMPORT_KEYRING: {
|
|
||||||
|
|
||||||
// Input
|
|
||||||
String keyServer = data.getString(IMPORT_KEY_SERVER);
|
|
||||||
ArrayList<ParcelableKeyRing> keyList = data.getParcelableArrayList(IMPORT_KEY_LIST);
|
|
||||||
|
|
||||||
// either keyList or cache must be null, no guarantees otherwise
|
|
||||||
if (keyList == null) {// import from file, do serially
|
|
||||||
serialKeyImport(null, keyServer, providerHelper);
|
|
||||||
} else {
|
|
||||||
// if there is more than one key with the same fingerprint, we do a serial import to prevent
|
|
||||||
// https://github.com/open-keychain/open-keychain/issues/1221
|
|
||||||
HashSet<String> keyFingerprintSet = new HashSet<>();
|
|
||||||
for (int i = 0; i < keyList.size(); i++) {
|
|
||||||
keyFingerprintSet.add(keyList.get(i).mExpectedFingerprint);
|
|
||||||
}
|
|
||||||
if (keyFingerprintSet.size() == keyList.size()) {
|
|
||||||
// all keys have unique fingerprints
|
|
||||||
multiThreadedKeyImport(keyList.iterator(), keyList.size(), keyServer);
|
|
||||||
} else {
|
|
||||||
serialKeyImport(keyList, keyServer, providerHelper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ACTION_UPLOAD_KEYRING: {
|
|
||||||
try {
|
|
||||||
|
|
||||||
// Input
|
|
||||||
String keyServer = data.getString(UPLOAD_KEY_SERVER);
|
|
||||||
// and dataUri!
|
|
||||||
|
|
||||||
// Operation
|
|
||||||
HkpKeyserver server = new HkpKeyserver(keyServer);
|
|
||||||
|
|
||||||
CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri);
|
|
||||||
ImportExportOperation importExportOperation = new ImportExportOperation(mKeychainService,
|
|
||||||
providerHelper, mKeychainService);
|
|
||||||
|
|
||||||
try {
|
|
||||||
importExportOperation.uploadKeyRingToServer(server, keyring);
|
|
||||||
} catch (Keyserver.AddKeyException e) {
|
|
||||||
throw new PgpGeneralException("Unable to export key to selected server");
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessageToHandler(MessageStatus.OKAY);
|
|
||||||
} catch (Exception e) {
|
|
||||||
sendErrorToHandler(e);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!intent.getAction().equals(ACTION_IMPORT_KEYRING)) {
|
|
||||||
// import keyring handles stopping service on its own
|
|
||||||
stopSelf();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -463,39 +151,6 @@ public class KeychainService extends Service implements Progressable {
|
|||||||
return START_NOT_STICKY;
|
return START_NOT_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendProofError(List<String> log, String label) {
|
|
||||||
String msg = null;
|
|
||||||
label = (label == null) ? "" : label + ": ";
|
|
||||||
for (String m : log) {
|
|
||||||
Log.e(Constants.TAG, label + m);
|
|
||||||
msg = m;
|
|
||||||
}
|
|
||||||
sendProofError(label + msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendProofError(String msg) {
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putString(ServiceProgressHandler.DATA_ERROR, msg);
|
|
||||||
sendMessageToHandler(MessageStatus.OKAY, bundle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendErrorToHandler(Exception e) {
|
|
||||||
// TODO: Implement a better exception handling here
|
|
||||||
// contextualize the exception, if necessary
|
|
||||||
String message;
|
|
||||||
if (e instanceof PgpGeneralMsgIdException) {
|
|
||||||
e = ((PgpGeneralMsgIdException) e).getContextualized(mKeychainService);
|
|
||||||
message = e.getMessage();
|
|
||||||
} else {
|
|
||||||
message = e.getMessage();
|
|
||||||
}
|
|
||||||
Log.d(Constants.TAG, "KeychainService Exception: ", e);
|
|
||||||
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
data.putString(ServiceProgressHandler.DATA_ERROR, message);
|
|
||||||
sendMessageToHandler(MessageStatus.EXCEPTION, null, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendMessageToHandler(MessageStatus status, Integer arg2, Bundle data) {
|
private void sendMessageToHandler(MessageStatus status, Integer arg2, Bundle data) {
|
||||||
|
|
||||||
Message msg = Message.obtain();
|
Message msg = Message.obtain();
|
||||||
@@ -509,7 +164,7 @@ public class KeychainService extends Service implements Progressable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mMessenger.send(msg);
|
mMessenger.get().send(msg);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
|
Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
@@ -523,10 +178,6 @@ public class KeychainService extends Service implements Progressable {
|
|||||||
sendMessageToHandler(status, null, bundle);
|
sendMessageToHandler(status, null, bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessageToHandler(MessageStatus status, Bundle data) {
|
|
||||||
sendMessageToHandler(status, null, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendMessageToHandler(MessageStatus status) {
|
private void sendMessageToHandler(MessageStatus status) {
|
||||||
sendMessageToHandler(status, null, null);
|
sendMessageToHandler(status, null, null);
|
||||||
}
|
}
|
||||||
@@ -564,214 +215,4 @@ public class KeychainService extends Service implements Progressable {
|
|||||||
sendMessageToHandler(MessageStatus.PREVENT_CANCEL);
|
sendMessageToHandler(MessageStatus.PREVENT_CANCEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void serialKeyImport(ArrayList<ParcelableKeyRing> keyList, final String keyServer,
|
|
||||||
ProviderHelper providerHelper) {
|
|
||||||
Log.d(Constants.TAG, "serial key import starting");
|
|
||||||
ParcelableFileCache<ParcelableKeyRing> cache =
|
|
||||||
new ParcelableFileCache<>(mKeychainService, "key_import.pcl");
|
|
||||||
|
|
||||||
// Operation
|
|
||||||
ImportExportOperation importExportOperation = new ImportExportOperation(
|
|
||||||
mKeychainService, providerHelper, mKeychainService,
|
|
||||||
mActionCanceled);
|
|
||||||
// Either list or cache must be null, no guarantees otherwise.
|
|
||||||
ImportKeyResult result = keyList != null
|
|
||||||
? importExportOperation.importKeyRings(keyList, keyServer)
|
|
||||||
: importExportOperation.importKeyRings(cache, keyServer);
|
|
||||||
|
|
||||||
ContactSyncAdapterService.requestSync();
|
|
||||||
// Result
|
|
||||||
sendMessageToHandler(MessageStatus.OKAY, result);
|
|
||||||
|
|
||||||
stopSelf();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void multiThreadedKeyImport(Iterator<ParcelableKeyRing> keyListIterator, int totKeys, final String
|
|
||||||
keyServer) {
|
|
||||||
Log.d(Constants.TAG, "Multi-threaded key import starting");
|
|
||||||
if (keyListIterator != null) {
|
|
||||||
mKeyImportAccumulator = new KeyImportAccumulator(totKeys, mKeychainService);
|
|
||||||
setProgress(0, totKeys);
|
|
||||||
|
|
||||||
final int maxThreads = 200;
|
|
||||||
ExecutorService importExecutor = new ThreadPoolExecutor(0, maxThreads,
|
|
||||||
30L, TimeUnit.SECONDS,
|
|
||||||
new SynchronousQueue<Runnable>());
|
|
||||||
|
|
||||||
while (keyListIterator.hasNext()) {
|
|
||||||
|
|
||||||
final ParcelableKeyRing pkRing = keyListIterator.next();
|
|
||||||
|
|
||||||
Runnable importOperationRunnable = new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
ImportKeyResult result = null;
|
|
||||||
try {
|
|
||||||
ImportExportOperation importExportOperation = new ImportExportOperation(
|
|
||||||
mKeychainService,
|
|
||||||
new ProviderHelper(mKeychainService),
|
|
||||||
mKeyImportAccumulator.getImportProgressable(),
|
|
||||||
mActionCanceled);
|
|
||||||
|
|
||||||
ArrayList<ParcelableKeyRing> list = new ArrayList<>();
|
|
||||||
list.add(pkRing);
|
|
||||||
|
|
||||||
result = importExportOperation.importKeyRings(list,
|
|
||||||
keyServer);
|
|
||||||
} finally {
|
|
||||||
// in the off-chance that importKeyRings does something to crash the
|
|
||||||
// thread before it can call singleKeyRingImportCompleted, our imported
|
|
||||||
// key count will go wrong. This will cause the service to never die,
|
|
||||||
// and the progress dialog to stay displayed. The finally block was
|
|
||||||
// originally meant to ensure singleKeyRingImportCompleted was called,
|
|
||||||
// and checks for null were to be introduced, but in such a scenario,
|
|
||||||
// knowing an uncaught error exists in importKeyRings is more important.
|
|
||||||
|
|
||||||
// if a null gets passed, something wrong is happening. We want a crash.
|
|
||||||
|
|
||||||
mKeyImportAccumulator.singleKeyRingImportCompleted(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
importExecutor.execute(importOperationRunnable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to accumulate the results of individual key imports
|
|
||||||
*/
|
|
||||||
private class KeyImportAccumulator {
|
|
||||||
private OperationResult.OperationLog mImportLog = new OperationResult.OperationLog();
|
|
||||||
private int mTotalKeys;
|
|
||||||
private int mImportedKeys = 0;
|
|
||||||
private Progressable mInternalProgressable;
|
|
||||||
ArrayList<Long> mImportedMasterKeyIds = new ArrayList<Long>();
|
|
||||||
private int mBadKeys = 0;
|
|
||||||
private int mNewKeys = 0;
|
|
||||||
private int mUpdatedKeys = 0;
|
|
||||||
private int mSecret = 0;
|
|
||||||
private int mResultType = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* meant to be used with a service due to stopSelf() in singleKeyRingImportCompleted. Remove this if
|
|
||||||
* generalising.
|
|
||||||
*
|
|
||||||
* @param totalKeys total number of keys to be imported
|
|
||||||
* @param externalProgressable the external progressable to be updated every time a key is imported
|
|
||||||
*/
|
|
||||||
public KeyImportAccumulator(int totalKeys, Progressable externalProgressable) {
|
|
||||||
mTotalKeys = totalKeys;
|
|
||||||
// ignore updates from ImportExportOperation for now
|
|
||||||
mInternalProgressable = new Progressable() {
|
|
||||||
@Override
|
|
||||||
public void setProgress(String message, int current, int total) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setProgress(int resourceId, int current, int total) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setProgress(int current, int total) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPreventCancel() {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void singleKeyRingImportCompleted(ImportKeyResult result) {
|
|
||||||
// increase imported key count and accumulate log and bad, new etc. key counts from result
|
|
||||||
mKeyImportAccumulator.accumulateKeyImport(result);
|
|
||||||
|
|
||||||
setProgress(mKeyImportAccumulator.getImportedKeys(), mKeyImportAccumulator.getTotalKeys());
|
|
||||||
|
|
||||||
if (mKeyImportAccumulator.isImportFinished()) {
|
|
||||||
ContactSyncAdapterService.requestSync();
|
|
||||||
|
|
||||||
sendMessageToHandler(ServiceProgressHandler.MessageStatus.OKAY,
|
|
||||||
mKeyImportAccumulator.getConsolidatedImportKeyResult());
|
|
||||||
|
|
||||||
stopSelf();//we're done here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Progressable getImportProgressable() {
|
|
||||||
return mInternalProgressable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTotalKeys() {
|
|
||||||
return mTotalKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getImportedKeys() {
|
|
||||||
return mImportedKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void accumulateKeyImport(ImportKeyResult result) {
|
|
||||||
mImportedKeys++;
|
|
||||||
mImportLog.addAll(result.getLog().toList());//accumulates log
|
|
||||||
mBadKeys += result.mBadKeys;
|
|
||||||
mNewKeys += result.mNewKeys;
|
|
||||||
mUpdatedKeys += result.mUpdatedKeys;
|
|
||||||
mSecret += result.mSecret;
|
|
||||||
|
|
||||||
long[] masterKeyIds = result.getImportedMasterKeyIds();
|
|
||||||
for (long masterKeyId : masterKeyIds) {
|
|
||||||
mImportedMasterKeyIds.add(masterKeyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if any key import has been cancelled, set result type to cancelled
|
|
||||||
// resultType is added to in getConsolidatedKayImport to account for remaining factors
|
|
||||||
mResultType |= result.getResult() & ImportKeyResult.RESULT_CANCELLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns accumulated result of all imports so far
|
|
||||||
*/
|
|
||||||
public ImportKeyResult getConsolidatedImportKeyResult() {
|
|
||||||
|
|
||||||
// adding required information to mResultType
|
|
||||||
// special case,no keys requested for import
|
|
||||||
if (mBadKeys == 0 && mNewKeys == 0 && mUpdatedKeys == 0) {
|
|
||||||
mResultType = ImportKeyResult.RESULT_FAIL_NOTHING;
|
|
||||||
} else {
|
|
||||||
if (mNewKeys > 0) {
|
|
||||||
mResultType |= ImportKeyResult.RESULT_OK_NEWKEYS;
|
|
||||||
}
|
|
||||||
if (mUpdatedKeys > 0) {
|
|
||||||
mResultType |= ImportKeyResult.RESULT_OK_UPDATED;
|
|
||||||
}
|
|
||||||
if (mBadKeys > 0) {
|
|
||||||
mResultType |= ImportKeyResult.RESULT_WITH_ERRORS;
|
|
||||||
if (mNewKeys == 0 && mUpdatedKeys == 0) {
|
|
||||||
mResultType |= ImportKeyResult.RESULT_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mImportLog.containsWarnings()) {
|
|
||||||
mResultType |= ImportKeyResult.RESULT_WARNINGS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
long masterKeyIds[] = new long[mImportedMasterKeyIds.size()];
|
|
||||||
for (int i = 0; i < masterKeyIds.length; i++) {
|
|
||||||
masterKeyIds[i] = mImportedMasterKeyIds.get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ImportKeyResult(mResultType, mImportLog, mNewKeys, mUpdatedKeys, mBadKeys,
|
|
||||||
mSecret, masterKeyIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isImportFinished() {
|
|
||||||
return mTotalKeys == mImportedKeys;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||||
|
* Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.service;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
public class PromoteKeyringParcel implements Parcelable {
|
||||||
|
|
||||||
|
public long mKeyRingId;
|
||||||
|
public byte[] mCardAid;
|
||||||
|
public long[] mSubKeyIds;
|
||||||
|
|
||||||
|
public PromoteKeyringParcel(long keyRingId, byte[] cardAid, long[] subKeyIds) {
|
||||||
|
mKeyRingId = keyRingId;
|
||||||
|
mCardAid = cardAid;
|
||||||
|
mSubKeyIds = subKeyIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PromoteKeyringParcel(Parcel in) {
|
||||||
|
mKeyRingId = in.readLong();
|
||||||
|
mCardAid = in.createByteArray();
|
||||||
|
mSubKeyIds = in.createLongArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeLong(mKeyRingId);
|
||||||
|
dest.writeByteArray(mCardAid);
|
||||||
|
dest.writeLongArray(mSubKeyIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<PromoteKeyringParcel> CREATOR = new Parcelable.Creator<PromoteKeyringParcel>() {
|
||||||
|
@Override
|
||||||
|
public PromoteKeyringParcel createFromParcel(Parcel in) {
|
||||||
|
return new PromoteKeyringParcel(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PromoteKeyringParcel[] newArray(int size) {
|
||||||
|
return new PromoteKeyringParcel[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -64,6 +64,8 @@ public class ServiceProgressHandler extends Handler {
|
|||||||
public static final String KEYBASE_PRESENCE_URL = "keybase_presence_url";
|
public static final String KEYBASE_PRESENCE_URL = "keybase_presence_url";
|
||||||
public static final String KEYBASE_PRESENCE_LABEL = "keybase_presence_label";
|
public static final String KEYBASE_PRESENCE_LABEL = "keybase_presence_label";
|
||||||
|
|
||||||
|
public static final String TAG_PROGRESS_DIALOG = "progressDialog";
|
||||||
|
|
||||||
FragmentActivity mActivity;
|
FragmentActivity mActivity;
|
||||||
|
|
||||||
public ServiceProgressHandler(FragmentActivity activity) {
|
public ServiceProgressHandler(FragmentActivity activity) {
|
||||||
@@ -88,7 +90,7 @@ public class ServiceProgressHandler extends Handler {
|
|||||||
Handler handler = new Handler();
|
Handler handler = new Handler();
|
||||||
handler.post(new Runnable() {
|
handler.post(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
frag.show(manager, "progressDialog");
|
frag.show(manager, TAG_PROGRESS_DIALOG);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -19,15 +19,12 @@
|
|||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.MatrixCursor;
|
import android.database.MatrixCursor;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
@@ -52,15 +49,11 @@ import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
|||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
||||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
|
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment;
|
import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;
|
import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@@ -302,7 +295,7 @@ public class CertifyKeyFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CertifyActionsParcel createOperationInput() {
|
public CertifyActionsParcel createOperationInput() {
|
||||||
|
|
||||||
// Bail out if there is not at least one user id selected
|
// Bail out if there is not at least one user id selected
|
||||||
ArrayList<CertifyAction> certifyActions = mUserIdsAdapter.getSelectedCertifyActions();
|
ArrayList<CertifyAction> certifyActions = mUserIdsAdapter.getSelectedCertifyActions();
|
||||||
@@ -325,7 +318,7 @@ public class CertifyKeyFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCryptoOperationSuccess(CertifyResult result) {
|
public void onCryptoOperationSuccess(CertifyResult result) {
|
||||||
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);
|
getActivity().setResult(Activity.RESULT_OK, intent);
|
||||||
@@ -333,7 +326,7 @@ public class CertifyKeyFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCryptoOperationCancelled() {
|
public void onCryptoOperationCancelled() {
|
||||||
super.onCryptoOperationCancelled();
|
super.onCryptoOperationCancelled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,25 +17,27 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.support.v4.app.FragmentActivity;
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.service.ConsolidateInputParcel;
|
||||||
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We can not directly create a dialog on the application context.
|
* We can not directly create a dialog on the application context.
|
||||||
* This activity encapsulates a DialogFragment to emulate a dialog.
|
* This activity encapsulates a DialogFragment to emulate a dialog.
|
||||||
*/
|
*/
|
||||||
public class ConsolidateDialogActivity extends FragmentActivity {
|
public class ConsolidateDialogActivity extends FragmentActivity
|
||||||
|
implements CryptoOperationHelper.Callback<ConsolidateInputParcel, ConsolidateResult> {
|
||||||
|
|
||||||
public static final String EXTRA_CONSOLIDATE_RECOVERY = "consolidate_recovery";
|
public static final String EXTRA_CONSOLIDATE_RECOVERY = "consolidate_recovery";
|
||||||
|
|
||||||
|
private CryptoOperationHelper<ConsolidateInputParcel, ConsolidateResult> mConsolidateOpHelper;
|
||||||
|
private boolean mRecovery;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -48,55 +50,45 @@ public class ConsolidateDialogActivity extends FragmentActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void consolidateRecovery(boolean recovery) {
|
private void consolidateRecovery(boolean recovery) {
|
||||||
// Message is received after importing is done in KeychainService
|
|
||||||
ServiceProgressHandler saveHandler = new ServiceProgressHandler(this) {
|
mRecovery = recovery;
|
||||||
|
|
||||||
|
mConsolidateOpHelper = new CryptoOperationHelper<>(this, this, R.string.progress_importing);
|
||||||
|
mConsolidateOpHelper.cryptoOperation();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message message) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
super.handleMessage(message);
|
if (mConsolidateOpHelper != null) {
|
||||||
|
mConsolidateOpHelper.handleActivityResult(requestCode, resultCode, data);
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
/* don't care about the results (for now?)
|
|
||||||
|
|
||||||
// get returned data bundle
|
|
||||||
Bundle returnData = message.getInputData();
|
|
||||||
if (returnData == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
final ConsolidateResult result =
|
|
||||||
returnData.getParcelable(KeychainService.RESULT_CONSOLIDATE);
|
|
||||||
if (result == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
result.createNotify(ConsolidateDialogActivity.this).show();
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConsolidateInputParcel createOperationInput() {
|
||||||
|
return new ConsolidateInputParcel(mRecovery);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(ConsolidateResult result) {
|
||||||
|
// don't care about result (for now?)
|
||||||
ConsolidateDialogActivity.this.finish();
|
ConsolidateDialogActivity.this.finish();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send all information needed to service to import key in other thread
|
@Override
|
||||||
Intent intent = new Intent(this, KeychainService.class);
|
public void onCryptoOperationCancelled() {
|
||||||
intent.setAction(KeychainService.ACTION_CONSOLIDATE);
|
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
data.putBoolean(KeychainService.CONSOLIDATE_RECOVERY, recovery);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(saveHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// show progress dialog
|
|
||||||
saveHandler.showProgressDialog(
|
|
||||||
getString(R.string.progress_importing),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, false
|
|
||||||
);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
startService(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(ConsolidateResult result) {
|
||||||
|
// don't care about result (for now?)
|
||||||
|
ConsolidateDialogActivity.this.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,12 +35,14 @@ import org.spongycastle.bcpg.sig.KeyFlags;
|
|||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
||||||
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;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
import org.sufficientlysecure.keychain.service.KeychainService;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
@@ -49,6 +51,7 @@ import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
|||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
||||||
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
@@ -68,6 +71,9 @@ public class CreateKeyFinalFragment extends CryptoOperationFragment<SaveKeyringP
|
|||||||
|
|
||||||
SaveKeyringParcel mSaveKeyringParcel;
|
SaveKeyringParcel mSaveKeyringParcel;
|
||||||
|
|
||||||
|
private CryptoOperationHelper<ExportKeyringParcel, ExportResult> mUploadOpHelper;
|
||||||
|
private CryptoOperationHelper<SaveKeyringParcel, EditKeyResult> mCreateOpHelper;
|
||||||
|
|
||||||
public static CreateKeyFinalFragment newInstance() {
|
public static CreateKeyFinalFragment newInstance() {
|
||||||
CreateKeyFinalFragment frag = new CreateKeyFinalFragment();
|
CreateKeyFinalFragment frag = new CreateKeyFinalFragment();
|
||||||
|
|
||||||
@@ -206,31 +212,20 @@ public class CreateKeyFinalFragment extends CryptoOperationFragment<SaveKeyringP
|
|||||||
private void createKey() {
|
private void createKey() {
|
||||||
final CreateKeyActivity createKeyActivity = (CreateKeyActivity) getActivity();
|
final CreateKeyActivity createKeyActivity = (CreateKeyActivity) getActivity();
|
||||||
|
|
||||||
Intent intent = new Intent(getActivity(), KeychainService.class);
|
CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult> createKeyCallback
|
||||||
intent.setAction(KeychainService.ACTION_EDIT_KEYRING);
|
= new CryptoOperationHelper.Callback<SaveKeyringParcel, EditKeyResult>() {
|
||||||
|
|
||||||
ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message message) {
|
public SaveKeyringParcel createOperationInput() {
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
return mSaveKeyringParcel;
|
||||||
super.handleMessage(message);
|
}
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
@Override
|
||||||
// get returned data bundle
|
public void onCryptoOperationSuccess(EditKeyResult result) {
|
||||||
Bundle returnData = message.getData();
|
|
||||||
if (returnData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final EditKeyResult result =
|
|
||||||
returnData.getParcelable(OperationResult.EXTRA_RESULT);
|
|
||||||
if (result == null) {
|
|
||||||
Log.e(Constants.TAG, "result == null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (createKeyActivity.mUseSmartCardSettings) {
|
if (createKeyActivity.mUseSmartCardSettings) {
|
||||||
// save key id in between
|
// save key id in between
|
||||||
mSaveKeyringParcel.mMasterKeyId = result.mMasterKeyId;
|
mSaveKeyringParcel.mMasterKeyId = result.mMasterKeyId;
|
||||||
|
// calls cryptoOperation corresponding to moveToCard
|
||||||
cryptoOperation(new CryptoInputParcel());
|
cryptoOperation(new CryptoInputParcel());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -246,26 +241,32 @@ public class CreateKeyFinalFragment extends CryptoOperationFragment<SaveKeyringP
|
|||||||
getActivity().setResult(Activity.RESULT_OK, data);
|
getActivity().setResult(Activity.RESULT_OK, data);
|
||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(EditKeyResult result) {
|
||||||
|
result.createNotify(getActivity()).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Bundle data = new Bundle();
|
mCreateOpHelper = new CryptoOperationHelper<>(this, createKeyCallback,
|
||||||
data.putParcelable(KeychainService.EDIT_KEYRING_PARCEL, mSaveKeyringParcel);
|
R.string.progress_building_key);
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
mCreateOpHelper.cryptoOperation();
|
||||||
Messenger messenger = new Messenger(saveHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
saveHandler.showProgressDialog(getString(R.string.progress_building_key),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, false);
|
|
||||||
|
|
||||||
getActivity().startService(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// currently only used for moveToCard
|
// currently only used for moveToCard
|
||||||
@Override
|
@Override
|
||||||
protected SaveKeyringParcel createOperationInput() {
|
public SaveKeyringParcel createOperationInput() {
|
||||||
CachedPublicKeyRing key = (new ProviderHelper(getActivity()))
|
CachedPublicKeyRing key = (new ProviderHelper(getActivity()))
|
||||||
.getCachedPublicKeyRing(mSaveKeyringParcel.mMasterKeyId);
|
.getCachedPublicKeyRing(mSaveKeyringParcel.mMasterKeyId);
|
||||||
|
|
||||||
@@ -297,7 +298,7 @@ public class CreateKeyFinalFragment extends CryptoOperationFragment<SaveKeyringP
|
|||||||
|
|
||||||
// currently only used for moveToCard
|
// currently only used for moveToCard
|
||||||
@Override
|
@Override
|
||||||
protected void onCryptoOperationSuccess(OperationResult result) {
|
public void onCryptoOperationSuccess(OperationResult result) {
|
||||||
EditKeyResult editResult = (EditKeyResult) result;
|
EditKeyResult editResult = (EditKeyResult) result;
|
||||||
|
|
||||||
if (editResult.mMasterKeyId != null && mUploadCheckbox.isChecked()) {
|
if (editResult.mMasterKeyId != null && mUploadCheckbox.isChecked()) {
|
||||||
@@ -314,33 +315,38 @@ public class CreateKeyFinalFragment extends CryptoOperationFragment<SaveKeyringP
|
|||||||
|
|
||||||
// TODO move into EditKeyOperation
|
// TODO move into EditKeyOperation
|
||||||
private void uploadKey(final EditKeyResult saveKeyResult) {
|
private void uploadKey(final EditKeyResult saveKeyResult) {
|
||||||
// Send all information needed to service to upload key in other thread
|
|
||||||
final Intent intent = new Intent(getActivity(), KeychainService.class);
|
|
||||||
|
|
||||||
intent.setAction(KeychainService.ACTION_UPLOAD_KEYRING);
|
|
||||||
|
|
||||||
// set data uri as path to keyring
|
// set data uri as path to keyring
|
||||||
Uri blobUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(
|
final Uri blobUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(
|
||||||
saveKeyResult.mMasterKeyId);
|
saveKeyResult.mMasterKeyId);
|
||||||
intent.setData(blobUri);
|
|
||||||
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
|
|
||||||
// upload to favorite keyserver
|
// upload to favorite keyserver
|
||||||
String keyserver = Preferences.getPreferences(getActivity()).getPreferredKeyserver();
|
final String keyserver = Preferences.getPreferences(getActivity()).getPreferredKeyserver();
|
||||||
data.putString(KeychainService.UPLOAD_KEY_SERVER, keyserver);
|
|
||||||
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
CryptoOperationHelper.Callback<ExportKeyringParcel, ExportResult> callback
|
||||||
|
= new CryptoOperationHelper.Callback<ExportKeyringParcel, ExportResult>() {
|
||||||
|
|
||||||
ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message message) {
|
public ExportKeyringParcel createOperationInput() {
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
return new ExportKeyringParcel(keyserver, blobUri);
|
||||||
super.handleMessage(message);
|
}
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
@Override
|
||||||
// TODO: upload operation needs a result!
|
public void onCryptoOperationSuccess(ExportResult result) {
|
||||||
// TODO: then combine these results
|
handleResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(ExportResult result) {
|
||||||
|
handleResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleResult(ExportResult result) {
|
||||||
|
// TODO: upload operation needs a result! "result" is not currenlty used
|
||||||
|
// TODO: then combine these results (saveKeyResult and update op result)
|
||||||
//if (result.getResult() == OperationResultParcel.RESULT_OK) {
|
//if (result.getResult() == OperationResultParcel.RESULT_OK) {
|
||||||
//Notify.create(getActivity(), R.string.key_send_success,
|
//Notify.create(getActivity(), R.string.key_send_success,
|
||||||
//Notify.Style.OK).show();
|
//Notify.Style.OK).show();
|
||||||
@@ -350,20 +356,16 @@ public class CreateKeyFinalFragment extends CryptoOperationFragment<SaveKeyringP
|
|||||||
getActivity().setResult(Activity.RESULT_OK, data);
|
getActivity().setResult(Activity.RESULT_OK, data);
|
||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(saveHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// show progress dialog
|
mUploadOpHelper = new CryptoOperationHelper<>(this, callback, R.string.progress_uploading);
|
||||||
saveHandler.showProgressDialog(
|
mUploadOpHelper.cryptoOperation();
|
||||||
getString(R.string.progress_uploading),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, false);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
getActivity().startService(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,8 @@ import java.nio.ByteBuffer;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -37,18 +34,19 @@ import android.widget.TextView;
|
|||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
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.DecryptVerifyResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
|
||||||
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.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
|
|
||||||
public class CreateKeyYubiKeyImportFragment extends Fragment implements NfcListenerFragment {
|
public class CreateKeyYubiKeyImportFragment
|
||||||
|
extends CryptoOperationFragment<ImportKeyringParcel, ImportKeyResult>
|
||||||
|
implements NfcListenerFragment {
|
||||||
|
|
||||||
private static final String ARG_FINGERPRINT = "fingerprint";
|
private static final String ARG_FINGERPRINT = "fingerprint";
|
||||||
public static final String ARG_AID = "aid";
|
public static final String ARG_AID = "aid";
|
||||||
@@ -64,6 +62,10 @@ public class CreateKeyYubiKeyImportFragment extends Fragment implements NfcListe
|
|||||||
private TextView vSerNo;
|
private TextView vSerNo;
|
||||||
private TextView vUserId;
|
private TextView vUserId;
|
||||||
|
|
||||||
|
// for CryptoOperationFragment key import
|
||||||
|
private String mKeyserver;
|
||||||
|
private ArrayList<ParcelableKeyRing> mKeyList;
|
||||||
|
|
||||||
public static Fragment newInstance(byte[] scannedFingerprints, byte[] nfcAid, String userId) {
|
public static Fragment newInstance(byte[] scannedFingerprints, byte[] nfcAid, String userId) {
|
||||||
|
|
||||||
CreateKeyYubiKeyImportFragment frag = new CreateKeyYubiKeyImportFragment();
|
CreateKeyYubiKeyImportFragment frag = new CreateKeyYubiKeyImportFragment();
|
||||||
@@ -175,77 +177,20 @@ public class CreateKeyYubiKeyImportFragment extends Fragment implements NfcListe
|
|||||||
|
|
||||||
public void importKey() {
|
public void importKey() {
|
||||||
|
|
||||||
// Message is received after decrypting is done in KeychainService
|
|
||||||
ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
|
||||||
super.handleMessage(message);
|
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
// get returned data bundle
|
|
||||||
Bundle returnData = message.getData();
|
|
||||||
|
|
||||||
ImportKeyResult result =
|
|
||||||
returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT);
|
|
||||||
|
|
||||||
long[] masterKeyIds = result.getImportedMasterKeyIds();
|
|
||||||
|
|
||||||
// TODO handle masterKeyIds.length != 1...? sorta outlandish scenario
|
|
||||||
|
|
||||||
if (!result.success() || masterKeyIds.length == 0) {
|
|
||||||
result.createNotify(getActivity()).show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Intent intent = new Intent(getActivity(), ViewKeyActivity.class);
|
|
||||||
// use the imported masterKeyId, not the one from the yubikey, because
|
|
||||||
// that one might* just have been a subkey of the imported key
|
|
||||||
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyIds[0]));
|
|
||||||
intent.putExtra(ViewKeyActivity.EXTRA_DISPLAY_RESULT, result);
|
|
||||||
intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
|
|
||||||
intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
|
|
||||||
intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
|
|
||||||
startActivity(intent);
|
|
||||||
getActivity().finish();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send all information needed to service to decrypt in other thread
|
|
||||||
Intent intent = new Intent(getActivity(), KeychainService.class);
|
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
|
|
||||||
intent.setAction(KeychainService.ACTION_IMPORT_KEYRING);
|
|
||||||
|
|
||||||
ArrayList<ParcelableKeyRing> keyList = new ArrayList<>();
|
ArrayList<ParcelableKeyRing> keyList = new ArrayList<>();
|
||||||
keyList.add(new ParcelableKeyRing(mNfcFingerprint, null, null));
|
keyList.add(new ParcelableKeyRing(mNfcFingerprint, null, null));
|
||||||
data.putParcelableArrayList(KeychainService.IMPORT_KEY_LIST, keyList);
|
mKeyList = keyList;
|
||||||
|
|
||||||
{
|
{
|
||||||
Preferences prefs = Preferences.getPreferences(getActivity());
|
Preferences prefs = Preferences.getPreferences(getActivity());
|
||||||
Preferences.CloudSearchPrefs cloudPrefs =
|
Preferences.CloudSearchPrefs cloudPrefs =
|
||||||
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
||||||
data.putString(KeychainService.IMPORT_KEY_SERVER, cloudPrefs.keyserver);
|
mKeyserver = cloudPrefs.keyserver;
|
||||||
}
|
}
|
||||||
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
super.setProgressMessageResource(R.string.progress_importing);
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
super.cryptoOperation();
|
||||||
Messenger messenger = new Messenger(saveHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
saveHandler.showProgressDialog(
|
|
||||||
getString(R.string.progress_importing),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, false
|
|
||||||
);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
getActivity().startService(intent);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,4 +209,29 @@ public class CreateKeyYubiKeyImportFragment extends Fragment implements NfcListe
|
|||||||
refreshSearch();
|
refreshSearch();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImportKeyringParcel createOperationInput() {
|
||||||
|
return new ImportKeyringParcel(mKeyList, mKeyserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(ImportKeyResult result) {
|
||||||
|
long[] masterKeyIds = result.getImportedMasterKeyIds();
|
||||||
|
if (masterKeyIds.length == 0) {
|
||||||
|
super.onCryptoOperationError(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent intent = new Intent(getActivity(), ViewKeyActivity.class);
|
||||||
|
// use the imported masterKeyId, not the one from the yubikey, because
|
||||||
|
// that one might* just have been a subkey of the imported key
|
||||||
|
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyIds[0]));
|
||||||
|
intent.putExtra(ViewKeyActivity.EXTRA_DISPLAY_RESULT, result);
|
||||||
|
intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
|
||||||
|
intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
|
||||||
|
intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
|
||||||
|
startActivity(intent);
|
||||||
|
getActivity().finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import android.os.Bundle;
|
|||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
@@ -45,14 +46,14 @@ import org.sufficientlysecure.keychain.R;
|
|||||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||||
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.pgp.KeyRing;
|
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
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.KeychainService;
|
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
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.ui.util.Notify;
|
||||||
@@ -78,6 +79,8 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager.
|
|||||||
private DecryptVerifyResult mDecryptVerifyResult;
|
private DecryptVerifyResult mDecryptVerifyResult;
|
||||||
private ViewAnimator mOverlayAnimator;
|
private ViewAnimator mOverlayAnimator;
|
||||||
|
|
||||||
|
private CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult> mImportOpHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
@@ -135,43 +138,15 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager.
|
|||||||
|
|
||||||
private void lookupUnknownKey(long unknownKeyId) {
|
private void lookupUnknownKey(long unknownKeyId) {
|
||||||
|
|
||||||
// Message is received after importing is done in KeychainService
|
final ArrayList<ParcelableKeyRing> keyList;
|
||||||
ServiceProgressHandler serviceHandler = new ServiceProgressHandler(getActivity()) {
|
final String keyserver;
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
|
||||||
super.handleMessage(message);
|
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
// get returned data bundle
|
|
||||||
Bundle returnData = message.getData();
|
|
||||||
|
|
||||||
if (returnData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ImportKeyResult result =
|
|
||||||
returnData.getParcelable(OperationResult.EXTRA_RESULT);
|
|
||||||
|
|
||||||
Activity activity = getActivity();
|
|
||||||
if (result != null && activity != null) {
|
|
||||||
result.createNotify(activity).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
getLoaderManager().restartLoader(LOADER_ID_UNIFIED, null, DecryptFragment.this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
|
|
||||||
// search config
|
// search config
|
||||||
{
|
{
|
||||||
Preferences prefs = Preferences.getPreferences(getActivity());
|
Preferences prefs = Preferences.getPreferences(getActivity());
|
||||||
Preferences.CloudSearchPrefs cloudPrefs =
|
Preferences.CloudSearchPrefs cloudPrefs =
|
||||||
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
||||||
data.putString(KeychainService.IMPORT_KEY_SERVER, cloudPrefs.keyserver);
|
keyserver = cloudPrefs.keyserver;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -180,19 +155,43 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager.
|
|||||||
ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>();
|
ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>();
|
||||||
selectedEntries.add(keyEntry);
|
selectedEntries.add(keyEntry);
|
||||||
|
|
||||||
data.putParcelableArrayList(KeychainService.IMPORT_KEY_LIST, selectedEntries);
|
keyList = selectedEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send all information needed to service to query keys in other thread
|
CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> callback
|
||||||
Intent intent = new Intent(getActivity(), KeychainService.class);
|
= new CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult>() {
|
||||||
intent.setAction(KeychainService.ACTION_IMPORT_KEYRING);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
@Override
|
||||||
Messenger messenger = new Messenger(serviceHandler);
|
public ImportKeyringParcel createOperationInput() {
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
return new ImportKeyringParcel(keyList, keyserver);
|
||||||
|
}
|
||||||
|
|
||||||
getActivity().startService(intent);
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(ImportKeyResult result) {
|
||||||
|
result.createNotify(getActivity()).show();
|
||||||
|
|
||||||
|
getLoaderManager().restartLoader(LOADER_ID_UNIFIED, null, DecryptFragment.this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(ImportKeyResult result) {
|
||||||
|
result.createNotify(getActivity()).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mImportOpHelper = new CryptoOperationHelper<>(this, callback, R.string.progress_importing);
|
||||||
|
|
||||||
|
mImportOpHelper.cryptoOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showKey(long keyId) {
|
private void showKey(long keyId) {
|
||||||
@@ -457,4 +456,11 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager.
|
|||||||
|
|
||||||
protected abstract void onVerifyLoaded(boolean hideErrorOverlay);
|
protected abstract void onVerifyLoaded(boolean hideErrorOverlay);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (mImportOpHelper != null) {
|
||||||
|
mImportOpHelper.handleActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,18 +254,12 @@ public class DecryptListFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onCryptoSetProgress(String msg, int progress, int max) {
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
mAdapter.setProgress(mCurrentInputUri, progress, max, msg);
|
mAdapter.setProgress(mCurrentInputUri, progress, max, msg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void dismissProgress() {
|
public void onCryptoOperationError(DecryptVerifyResult result) {
|
||||||
// progress shown inline, so never mind
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCryptoOperationError(DecryptVerifyResult result) {
|
|
||||||
final Uri uri = mCurrentInputUri;
|
final Uri uri = mCurrentInputUri;
|
||||||
mCurrentInputUri = null;
|
mCurrentInputUri = null;
|
||||||
|
|
||||||
@@ -275,7 +269,7 @@ public class DecryptListFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCryptoOperationSuccess(DecryptVerifyResult result) {
|
public void onCryptoOperationSuccess(DecryptVerifyResult result) {
|
||||||
Uri uri = mCurrentInputUri;
|
Uri uri = mCurrentInputUri;
|
||||||
mCurrentInputUri = null;
|
mCurrentInputUri = null;
|
||||||
|
|
||||||
@@ -439,7 +433,7 @@ public class DecryptListFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PgpDecryptVerifyInputParcel createOperationInput() {
|
public PgpDecryptVerifyInputParcel createOperationInput() {
|
||||||
|
|
||||||
if (mCurrentInputUri == null) {
|
if (mCurrentInputUri == null) {
|
||||||
if (mPendingInputUris.isEmpty()) {
|
if (mPendingInputUris.isEmpty()) {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -26,7 +25,6 @@ import android.os.Bundle;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
import android.os.Parcelable;
|
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
@@ -40,9 +38,6 @@ import android.widget.ListView;
|
|||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
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.SingletonResult;
|
import org.sufficientlysecure.keychain.operations.results.SingletonResult;
|
||||||
@@ -54,8 +49,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
|
|||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
|
||||||
@@ -65,7 +58,12 @@ 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.CryptoOperationFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.*;
|
import org.sufficientlysecure.keychain.ui.dialog.AddSubkeyDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.AddUserIdDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyExpiryDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.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;
|
||||||
@@ -609,12 +607,12 @@ public class EditKeyFragment extends CryptoOperationFragment<SaveKeyringParcel,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SaveKeyringParcel createOperationInput() {
|
public SaveKeyringParcel createOperationInput() {
|
||||||
return mSaveKeyringParcel;
|
return mSaveKeyringParcel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCryptoOperationSuccess(OperationResult result) {
|
public void onCryptoOperationSuccess(OperationResult result) {
|
||||||
|
|
||||||
// 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();
|
||||||
|
|||||||
@@ -386,7 +386,7 @@ public class EncryptFilesFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCryptoOperationSuccess(final SignEncryptResult result) {
|
public void onCryptoOperationSuccess(final SignEncryptResult result) {
|
||||||
|
|
||||||
if (mDeleteAfterEncrypt) {
|
if (mDeleteAfterEncrypt) {
|
||||||
// TODO make behavior coherent here
|
// TODO make behavior coherent here
|
||||||
@@ -485,7 +485,7 @@ public class EncryptFilesFragment
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SignEncryptParcel createOperationInput() {
|
public SignEncryptParcel createOperationInput() {
|
||||||
|
|
||||||
SignEncryptParcel actionsParcel = getCachedActionsParcel();
|
SignEncryptParcel actionsParcel = getCachedActionsParcel();
|
||||||
|
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ public class EncryptTextFragment
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SignEncryptParcel createOperationInput() {
|
public SignEncryptParcel createOperationInput() {
|
||||||
|
|
||||||
if (mMessage == null || mMessage.isEmpty()) {
|
if (mMessage == null || mMessage.isEmpty()) {
|
||||||
Notify.create(getActivity(), R.string.error_empty_text, Notify.Style.ERROR)
|
Notify.create(getActivity(), R.string.error_empty_text, Notify.Style.ERROR)
|
||||||
@@ -316,7 +316,7 @@ public class EncryptTextFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCryptoOperationSuccess(SignEncryptResult result) {
|
public void onCryptoOperationSuccess(SignEncryptResult result) {
|
||||||
|
|
||||||
if (mShareAfterEncrypt) {
|
if (mShareAfterEncrypt) {
|
||||||
// Share encrypted message/file
|
// Share encrypted message/file
|
||||||
|
|||||||
@@ -17,12 +17,10 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Messenger;
|
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
@@ -35,9 +33,10 @@ import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
|
|||||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||||
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.service.KeychainService;
|
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
|
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
||||||
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
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;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
@@ -47,7 +46,8 @@ import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class ImportKeysActivity extends BaseNfcActivity {
|
public class ImportKeysActivity extends BaseNfcActivity
|
||||||
|
implements CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> {
|
||||||
|
|
||||||
public static final String ACTION_IMPORT_KEY = OpenKeychainIntents.IMPORT_KEY;
|
public static final String ACTION_IMPORT_KEY = OpenKeychainIntents.IMPORT_KEY;
|
||||||
public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = OpenKeychainIntents.IMPORT_KEY_FROM_KEYSERVER;
|
public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = OpenKeychainIntents.IMPORT_KEY_FROM_KEYSERVER;
|
||||||
@@ -82,6 +82,12 @@ public class ImportKeysActivity extends BaseNfcActivity {
|
|||||||
private Fragment mTopFragment;
|
private Fragment mTopFragment;
|
||||||
private View mImportButton;
|
private View mImportButton;
|
||||||
|
|
||||||
|
// for CryptoOperationHelper.Callback
|
||||||
|
private String mKeyserver;
|
||||||
|
private ArrayList<ParcelableKeyRing> mKeyList;
|
||||||
|
|
||||||
|
private CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult> mOperationHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -388,23 +394,9 @@ public class ImportKeysActivity extends BaseNfcActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServiceProgressHandler serviceHandler = new ServiceProgressHandler(this) {
|
mOperationHelper = new CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult>(
|
||||||
@Override
|
this, this, R.string.progress_importing
|
||||||
public void handleMessage(Message message) {
|
);
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
|
||||||
super.handleMessage(message);
|
|
||||||
|
|
||||||
ImportKeysActivity.this.handleMessage(message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send all information needed to service to import key in other thread
|
|
||||||
Intent intent = new Intent(this, KeychainService.class);
|
|
||||||
|
|
||||||
intent.setAction(KeychainService.ACTION_IMPORT_KEYRING);
|
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
|
|
||||||
ImportKeysListFragment.LoaderState ls = mListFragment.getLoaderState();
|
ImportKeysListFragment.LoaderState ls = mListFragment.getLoaderState();
|
||||||
if (ls instanceof ImportKeysListFragment.BytesLoaderState) {
|
if (ls instanceof ImportKeysListFragment.BytesLoaderState) {
|
||||||
@@ -423,30 +415,18 @@ public class ImportKeysActivity extends BaseNfcActivity {
|
|||||||
new ParcelableFileCache<>(this, "key_import.pcl");
|
new ParcelableFileCache<>(this, "key_import.pcl");
|
||||||
cache.writeCache(selectedEntries);
|
cache.writeCache(selectedEntries);
|
||||||
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
mKeyList = null;
|
||||||
|
mKeyserver = null;
|
||||||
|
mOperationHelper.cryptoOperation();
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(serviceHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// show progress dialog
|
|
||||||
serviceHandler.showProgressDialog(
|
|
||||||
getString(R.string.progress_importing),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
startService(intent);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(Constants.TAG, "Problem writing cache file", e);
|
Log.e(Constants.TAG, "Problem writing cache file", e);
|
||||||
Notify.create(this, "Problem writing cache file!", Notify.Style.ERROR)
|
Notify.create(this, "Problem writing cache file!", Notify.Style.ERROR)
|
||||||
.show((ViewGroup) findViewById(R.id.import_snackbar));
|
.show((ViewGroup) findViewById(R.id.import_snackbar));
|
||||||
}
|
}
|
||||||
} else if (ls instanceof ImportKeysListFragment.CloudLoaderState) {
|
} else if (ls instanceof ImportKeysListFragment.CloudLoaderState) {
|
||||||
ImportKeysListFragment.CloudLoaderState sls = (ImportKeysListFragment.CloudLoaderState) ls;
|
ImportKeysListFragment.CloudLoaderState sls =
|
||||||
|
(ImportKeysListFragment.CloudLoaderState) ls;
|
||||||
data.putString(KeychainService.IMPORT_KEY_SERVER, sls.mCloudPrefs.keyserver);
|
|
||||||
|
|
||||||
// get selected key entries
|
// get selected key entries
|
||||||
ArrayList<ParcelableKeyRing> keys = new ArrayList<>();
|
ArrayList<ParcelableKeyRing> keys = new ArrayList<>();
|
||||||
@@ -459,22 +439,11 @@ public class ImportKeysActivity extends BaseNfcActivity {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.putParcelableArrayList(KeychainService.IMPORT_KEY_LIST, keys);
|
|
||||||
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
mKeyList = keys;
|
||||||
|
mKeyserver = sls.mCloudPrefs.keyserver;
|
||||||
|
mOperationHelper.cryptoOperation();
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(serviceHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// show progress dialog
|
|
||||||
serviceHandler.showProgressDialog(
|
|
||||||
getString(R.string.progress_importing),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, true
|
|
||||||
);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
startService(intent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,4 +454,57 @@ public class ImportKeysActivity extends BaseNfcActivity {
|
|||||||
// either way, finish afterwards
|
// either way, finish afterwards
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (mOperationHelper == null ||
|
||||||
|
!mOperationHelper.handleActivityResult(requestCode, resultCode, data)) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleResult (ImportKeyResult result) {
|
||||||
|
if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction())
|
||||||
|
|| ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.putExtra(ImportKeyResult.EXTRA_RESULT, result);
|
||||||
|
ImportKeysActivity.this.setResult(RESULT_OK, intent);
|
||||||
|
ImportKeysActivity.this.finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(getIntent().getAction())) {
|
||||||
|
ImportKeysActivity.this.setResult(RESULT_OK, mPendingIntentData);
|
||||||
|
ImportKeysActivity.this.finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.createNotify(ImportKeysActivity.this)
|
||||||
|
.show((ViewGroup) findViewById(R.id.import_snackbar));
|
||||||
|
}
|
||||||
|
// methods from CryptoOperationHelper.Callback
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImportKeyringParcel createOperationInput() {
|
||||||
|
return new ImportKeyringParcel(mKeyList, mKeyserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(ImportKeyResult result) {
|
||||||
|
handleResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(ImportKeyResult result) {
|
||||||
|
handleResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -26,8 +25,6 @@ import android.nfc.NdefMessage;
|
|||||||
import android.nfc.NfcAdapter;
|
import android.nfc.NfcAdapter;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.support.v4.app.FragmentActivity;
|
import android.support.v4.app.FragmentActivity;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@@ -43,8 +40,8 @@ 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.operations.results.OperationResult.LogType;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||||
import org.sufficientlysecure.keychain.operations.results.SingletonResult;
|
import org.sufficientlysecure.keychain.operations.results.SingletonResult;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4;
|
import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
@@ -55,7 +52,8 @@ import java.util.Locale;
|
|||||||
/**
|
/**
|
||||||
* Proxy activity (just a transparent content view) to scan QR Codes using the Barcode Scanner app
|
* Proxy activity (just a transparent content view) to scan QR Codes using the Barcode Scanner app
|
||||||
*/
|
*/
|
||||||
public class ImportKeysProxyActivity extends FragmentActivity {
|
public class ImportKeysProxyActivity extends FragmentActivity
|
||||||
|
implements CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> {
|
||||||
|
|
||||||
public static final String ACTION_QR_CODE_API = OpenKeychainIntents.IMPORT_KEY_FROM_QR_CODE;
|
public static final String ACTION_QR_CODE_API = OpenKeychainIntents.IMPORT_KEY_FROM_QR_CODE;
|
||||||
// implies activity returns scanned fingerprint as extra and does not import
|
// implies activity returns scanned fingerprint as extra and does not import
|
||||||
@@ -64,6 +62,11 @@ public class ImportKeysProxyActivity extends FragmentActivity {
|
|||||||
|
|
||||||
public static final String EXTRA_FINGERPRINT = "fingerprint";
|
public static final String EXTRA_FINGERPRINT = "fingerprint";
|
||||||
|
|
||||||
|
// for CryptoOperationHelper
|
||||||
|
private String mKeyserver;
|
||||||
|
private ArrayList<ParcelableKeyRing> mKeyList;
|
||||||
|
private CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult> mImportOpHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -106,6 +109,10 @@ public class ImportKeysProxyActivity extends FragmentActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (mImportOpHelper != null) {
|
||||||
|
mImportOpHelper.cryptoOperation();
|
||||||
|
}
|
||||||
|
|
||||||
if (requestCode == IntentIntegratorSupportV4.REQUEST_CODE) {
|
if (requestCode == IntentIntegratorSupportV4.REQUEST_CODE) {
|
||||||
IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode,
|
IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode,
|
||||||
resultCode, data);
|
resultCode, data);
|
||||||
@@ -205,75 +212,56 @@ public class ImportKeysProxyActivity extends FragmentActivity {
|
|||||||
|
|
||||||
private void startImportService(ArrayList<ParcelableKeyRing> keyRings) {
|
private void startImportService(ArrayList<ParcelableKeyRing> keyRings) {
|
||||||
|
|
||||||
// Message is received after importing is done in KeychainService
|
// search config
|
||||||
ServiceProgressHandler serviceHandler = new ServiceProgressHandler(this) {
|
{
|
||||||
|
Preferences prefs = Preferences.getPreferences(this);
|
||||||
|
Preferences.CloudSearchPrefs cloudPrefs =
|
||||||
|
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
||||||
|
mKeyserver = cloudPrefs.keyserver;
|
||||||
|
}
|
||||||
|
|
||||||
|
mKeyList = keyRings;
|
||||||
|
|
||||||
|
mImportOpHelper = new CryptoOperationHelper<>(this, this, R.string.progress_importing);
|
||||||
|
|
||||||
|
mImportOpHelper.cryptoOperation();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// CryptoOperationHelper.Callback methods
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message message) {
|
public ImportKeyringParcel createOperationInput() {
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
return new ImportKeyringParcel(mKeyList, mKeyserver);
|
||||||
super.handleMessage(message);
|
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
// get returned data bundle
|
|
||||||
Bundle returnData = message.getData();
|
|
||||||
if (returnData == null) {
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final ImportKeyResult result =
|
|
||||||
returnData.getParcelable(OperationResult.EXTRA_RESULT);
|
|
||||||
if (result == null) {
|
|
||||||
Log.e(Constants.TAG, "result == null");
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.success()) {
|
@Override
|
||||||
// only return if no success...
|
public void onCryptoOperationSuccess(ImportKeyResult result) {
|
||||||
|
Intent certifyIntent = new Intent(this, CertifyKeyActivity.class);
|
||||||
|
certifyIntent.putExtra(CertifyKeyActivity.EXTRA_RESULT, result);
|
||||||
|
certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS,
|
||||||
|
result.getImportedMasterKeyIds());
|
||||||
|
startActivityForResult(certifyIntent, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(ImportKeyResult result) {
|
||||||
|
Bundle returnData = new Bundle();
|
||||||
|
returnData.putParcelable(OperationResult.EXTRA_RESULT, result);
|
||||||
Intent data = new Intent();
|
Intent data = new Intent();
|
||||||
data.putExtras(returnData);
|
data.putExtras(returnData);
|
||||||
returnResult(data);
|
returnResult(data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent certifyIntent = new Intent(ImportKeysProxyActivity.this,
|
@Override
|
||||||
CertifyKeyActivity.class);
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
certifyIntent.putExtra(CertifyKeyActivity.EXTRA_RESULT, result);
|
return false;
|
||||||
certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS,
|
|
||||||
result.getImportedMasterKeyIds());
|
|
||||||
startActivityForResult(certifyIntent, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
|
|
||||||
// search config
|
|
||||||
{
|
|
||||||
Preferences prefs = Preferences.getPreferences(this);
|
|
||||||
Preferences.CloudSearchPrefs cloudPrefs =
|
|
||||||
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
|
||||||
data.putString(KeychainService.IMPORT_KEY_SERVER, cloudPrefs.keyserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.putParcelableArrayList(KeychainService.IMPORT_KEY_LIST, keyRings);
|
|
||||||
|
|
||||||
// Send all information needed to service to query keys in other thread
|
|
||||||
Intent intent = new Intent(this, KeychainService.class);
|
|
||||||
intent.setAction(KeychainService.ACTION_IMPORT_KEYRING);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(serviceHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// show progress dialog
|
|
||||||
serviceHandler.showProgressDialog(
|
|
||||||
getString(R.string.progress_importing),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, true);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
startService(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
import android.animation.ObjectAnimator;
|
import android.animation.ObjectAnimator;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
@@ -64,9 +63,10 @@ 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.KeychainDatabase;
|
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
import org.sufficientlysecure.keychain.service.ConsolidateInputParcel;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||||
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
|
||||||
@@ -90,7 +90,8 @@ import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
|
|||||||
*/
|
*/
|
||||||
public class KeyListFragment extends LoaderFragment
|
public class KeyListFragment extends LoaderFragment
|
||||||
implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener,
|
implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener,
|
||||||
LoaderManager.LoaderCallbacks<Cursor>, FabContainer {
|
LoaderManager.LoaderCallbacks<Cursor>, FabContainer,
|
||||||
|
CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> {
|
||||||
|
|
||||||
static final int REQUEST_REPEAT_PASSPHRASE = 1;
|
static final int REQUEST_REPEAT_PASSPHRASE = 1;
|
||||||
static final int REQUEST_ACTION = 2;
|
static final int REQUEST_ACTION = 2;
|
||||||
@@ -107,6 +108,14 @@ public class KeyListFragment extends LoaderFragment
|
|||||||
|
|
||||||
private FloatingActionsMenu mFab;
|
private FloatingActionsMenu mFab;
|
||||||
|
|
||||||
|
// for CryptoOperationHelper import
|
||||||
|
private ArrayList<ParcelableKeyRing> mKeyList;
|
||||||
|
private String mKeyserver;
|
||||||
|
private CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult> mImportOpHelper;
|
||||||
|
|
||||||
|
// for ConsolidateOperation
|
||||||
|
private CryptoOperationHelper<ConsolidateInputParcel, ConsolidateResult> mConsolidateOpHelper;
|
||||||
|
|
||||||
// This ids for multiple key export.
|
// This ids for multiple key export.
|
||||||
private ArrayList<Long> mIdsForRepeatAskPassphrase;
|
private ArrayList<Long> mIdsForRepeatAskPassphrase;
|
||||||
// This index for remembering the number of master key.
|
// This index for remembering the number of master key.
|
||||||
@@ -580,112 +589,59 @@ public class KeyListFragment extends LoaderFragment
|
|||||||
ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null);
|
ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null);
|
||||||
keyList.add(keyEntry);
|
keyList.add(keyEntry);
|
||||||
}
|
}
|
||||||
|
mKeyList = keyList;
|
||||||
} finally {
|
} finally {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
ServiceProgressHandler serviceHandler = new ServiceProgressHandler(getActivity()) {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
|
||||||
super.handleMessage(message);
|
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
// get returned data bundle
|
|
||||||
Bundle returnData = message.getData();
|
|
||||||
if (returnData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final ImportKeyResult result =
|
|
||||||
returnData.getParcelable(OperationResult.EXTRA_RESULT);
|
|
||||||
if (result == null) {
|
|
||||||
Log.e(Constants.TAG, "result == null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.createNotify(getActivity()).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send all information needed to service to query keys in other thread
|
|
||||||
Intent intent = new Intent(getActivity(), KeychainService.class);
|
|
||||||
intent.setAction(KeychainService.ACTION_IMPORT_KEYRING);
|
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
|
|
||||||
// search config
|
// search config
|
||||||
{
|
{
|
||||||
Preferences prefs = Preferences.getPreferences(getActivity());
|
Preferences prefs = Preferences.getPreferences(getActivity());
|
||||||
Preferences.CloudSearchPrefs cloudPrefs =
|
Preferences.CloudSearchPrefs cloudPrefs =
|
||||||
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
||||||
data.putString(KeychainService.IMPORT_KEY_SERVER, cloudPrefs.keyserver);
|
mKeyserver = cloudPrefs.keyserver;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.putParcelableArrayList(KeychainService.IMPORT_KEY_LIST, keyList);
|
mImportOpHelper = new CryptoOperationHelper<>(this,
|
||||||
|
this, R.string.progress_updating);
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
mImportOpHelper.cryptoOperation();
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(serviceHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// show progress dialog
|
|
||||||
serviceHandler.showProgressDialog(
|
|
||||||
getString(R.string.progress_updating),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, true);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
getActivity().startService(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void consolidate() {
|
private void consolidate() {
|
||||||
// Message is received after importing is done in KeychainService
|
|
||||||
ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
|
CryptoOperationHelper.Callback<ConsolidateInputParcel, ConsolidateResult> callback
|
||||||
|
= new CryptoOperationHelper.Callback<ConsolidateInputParcel, ConsolidateResult>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message message) {
|
public ConsolidateInputParcel createOperationInput() {
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
return new ConsolidateInputParcel(false); // we want to perform a full consolidate
|
||||||
super.handleMessage(message);
|
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
// get returned data bundle
|
|
||||||
Bundle returnData = message.getData();
|
|
||||||
if (returnData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final ConsolidateResult result =
|
|
||||||
returnData.getParcelable(OperationResult.EXTRA_RESULT);
|
|
||||||
if (result == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(ConsolidateResult result) {
|
||||||
result.createNotify(getActivity()).show();
|
result.createNotify(getActivity()).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(ConsolidateResult result) {
|
||||||
|
result.createNotify(getActivity()).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send all information needed to service to import key in other thread
|
mConsolidateOpHelper =
|
||||||
Intent intent = new Intent(getActivity(), KeychainService.class);
|
new CryptoOperationHelper<>(this, callback, R.string.progress_importing);
|
||||||
|
|
||||||
intent.setAction(KeychainService.ACTION_CONSOLIDATE);
|
mConsolidateOpHelper.cryptoOperation();
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(saveHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// show progress dialog
|
|
||||||
saveHandler.showProgressDialog(
|
|
||||||
getString(R.string.progress_importing),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, false);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
getActivity().startService(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMultiExportDialog(long[] masterKeyIds) {
|
private void showMultiExportDialog(long[] masterKeyIds) {
|
||||||
@@ -724,6 +680,14 @@ public class KeyListFragment extends LoaderFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (mImportOpHelper != null) {
|
||||||
|
mImportOpHelper.handleActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mConsolidateOpHelper != null) {
|
||||||
|
mConsolidateOpHelper.handleActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
if (requestCode == REQUEST_REPEAT_PASSPHRASE) {
|
if (requestCode == REQUEST_REPEAT_PASSPHRASE) {
|
||||||
if (resultCode != Activity.RESULT_OK) {
|
if (resultCode != Activity.RESULT_OK) {
|
||||||
return;
|
return;
|
||||||
@@ -769,6 +733,32 @@ public class KeyListFragment extends LoaderFragment
|
|||||||
anim.start();
|
anim.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CryptoOperationHelper.Callback methods
|
||||||
|
@Override
|
||||||
|
public ImportKeyringParcel createOperationInput() {
|
||||||
|
return new ImportKeyringParcel(mKeyList, mKeyserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(ImportKeyResult result) {
|
||||||
|
result.createNotify(getActivity()).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(ImportKeyResult result) {
|
||||||
|
result.createNotify(getActivity()).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public class KeyListAdapter extends KeyAdapter implements StickyListHeadersAdapter {
|
public class KeyListAdapter extends KeyAdapter implements StickyListHeadersAdapter {
|
||||||
|
|
||||||
private HashMap<Integer, Boolean> mSelection = new HashMap<>();
|
private HashMap<Integer, Boolean> mSelection = new HashMap<>();
|
||||||
|
|||||||
@@ -18,15 +18,11 @@
|
|||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.support.v4.app.FragmentActivity;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.NumberPicker;
|
import android.widget.NumberPicker;
|
||||||
@@ -38,9 +34,9 @@ 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.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
|
import org.sufficientlysecure.keychain.util.ParcelableFileCache;
|
||||||
@@ -52,7 +48,8 @@ import edu.cmu.cylab.starslinger.exchange.ExchangeActivity;
|
|||||||
import edu.cmu.cylab.starslinger.exchange.ExchangeConfig;
|
import edu.cmu.cylab.starslinger.exchange.ExchangeConfig;
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
public class SafeSlingerActivity extends BaseActivity {
|
public class SafeSlingerActivity extends BaseActivity
|
||||||
|
implements CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> {
|
||||||
|
|
||||||
private static final int REQUEST_CODE_SAFE_SLINGER = 211;
|
private static final int REQUEST_CODE_SAFE_SLINGER = 211;
|
||||||
|
|
||||||
@@ -61,6 +58,12 @@ public class SafeSlingerActivity extends BaseActivity {
|
|||||||
private long mMasterKeyId;
|
private long mMasterKeyId;
|
||||||
private int mSelectedNumber = 2;
|
private int mSelectedNumber = 2;
|
||||||
|
|
||||||
|
// for CryptoOperationHelper
|
||||||
|
private ArrayList<ParcelableKeyRing> mKeyList;
|
||||||
|
private String mKeyserver;
|
||||||
|
private CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult> mOperationHelper;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -116,65 +119,17 @@ public class SafeSlingerActivity extends BaseActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (mOperationHelper != null) {
|
||||||
|
mOperationHelper.handleActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
if (requestCode == REQUEST_CODE_SAFE_SLINGER) {
|
if (requestCode == REQUEST_CODE_SAFE_SLINGER) {
|
||||||
if (resultCode == ExchangeActivity.RESULT_EXCHANGE_CANCELED) {
|
if (resultCode == ExchangeActivity.RESULT_EXCHANGE_CANCELED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final FragmentActivity activity = SafeSlingerActivity.this;
|
|
||||||
|
|
||||||
// Message is received after importing is done in KeychainService
|
|
||||||
ServiceProgressHandler saveHandler = new ServiceProgressHandler(activity) {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
|
||||||
super.handleMessage(message);
|
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
// get returned data bundle
|
|
||||||
Bundle returnData = message.getData();
|
|
||||||
if (returnData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final ImportKeyResult result =
|
|
||||||
returnData.getParcelable(OperationResult.EXTRA_RESULT);
|
|
||||||
if (result == null) {
|
|
||||||
Log.e(Constants.TAG, "result == null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.success()) {
|
|
||||||
// result.createNotify(activity).show();
|
|
||||||
// only return if no success...
|
|
||||||
Intent data = new Intent();
|
|
||||||
data.putExtras(returnData);
|
|
||||||
setResult(RESULT_OK, data);
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (mExchangeMasterKeyId == null) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
Intent certifyIntent = new Intent(activity, CertifyKeyActivity.class);
|
|
||||||
certifyIntent.putExtra(CertifyKeyActivity.EXTRA_RESULT, result);
|
|
||||||
certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, result.getImportedMasterKeyIds());
|
|
||||||
certifyIntent.putExtra(CertifyKeyActivity.EXTRA_CERTIFY_KEY_ID, mMasterKeyId);
|
|
||||||
startActivityForResult(certifyIntent, 0);
|
|
||||||
|
|
||||||
// mExchangeMasterKeyId = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Log.d(Constants.TAG, "importKeys started");
|
Log.d(Constants.TAG, "importKeys started");
|
||||||
|
|
||||||
// Send all information needed to service to import key in other thread
|
|
||||||
Intent intent = new Intent(activity, KeychainService.class);
|
|
||||||
|
|
||||||
intent.setAction(KeychainService.ACTION_IMPORT_KEYRING);
|
|
||||||
|
|
||||||
// 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
|
||||||
// read FileImportCache for more info.
|
// read FileImportCache for more info.
|
||||||
@@ -185,28 +140,18 @@ public class SafeSlingerActivity extends BaseActivity {
|
|||||||
// We parcel this iteratively into a file - anything we can
|
// We parcel this iteratively into a file - anything we can
|
||||||
// display here, we should be able to import.
|
// display here, we should be able to import.
|
||||||
ParcelableFileCache<ParcelableKeyRing> cache =
|
ParcelableFileCache<ParcelableKeyRing> cache =
|
||||||
new ParcelableFileCache<>(activity, "key_import.pcl");
|
new ParcelableFileCache<>(this, "key_import.pcl");
|
||||||
cache.writeCache(it.size(), it.iterator());
|
cache.writeCache(it.size(), it.iterator());
|
||||||
|
|
||||||
// fill values for this action
|
mOperationHelper =
|
||||||
Bundle bundle = new Bundle();
|
new CryptoOperationHelper(this, this, R.string.progress_importing);
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, bundle);
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
mKeyList = null;
|
||||||
Messenger messenger = new Messenger(saveHandler);
|
mKeyserver = null;
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
mOperationHelper.cryptoOperation();
|
||||||
|
|
||||||
// show progress dialog
|
|
||||||
saveHandler.showProgressDialog(
|
|
||||||
getString(R.string.progress_importing),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, true
|
|
||||||
);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
activity.startService(intent);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(Constants.TAG, "Problem writing cache file", e);
|
Log.e(Constants.TAG, "Problem writing cache file", e);
|
||||||
Notify.create(activity, "Problem writing cache file!", Notify.Style.ERROR).show();
|
Notify.create(this, "Problem writing cache file!", Notify.Style.ERROR).show();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// give everything else down to KeyListActivity!
|
// give everything else down to KeyListActivity!
|
||||||
@@ -233,4 +178,39 @@ public class SafeSlingerActivity extends BaseActivity {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CryptoOperationHelper.Callback functions
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImportKeyringParcel createOperationInput() {
|
||||||
|
return new ImportKeyringParcel(mKeyList, mKeyserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(ImportKeyResult result) {
|
||||||
|
Intent certifyIntent = new Intent(this, CertifyKeyActivity.class);
|
||||||
|
certifyIntent.putExtra(CertifyKeyActivity.EXTRA_RESULT, result);
|
||||||
|
certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, result.getImportedMasterKeyIds());
|
||||||
|
certifyIntent.putExtra(CertifyKeyActivity.EXTRA_CERTIFY_KEY_ID, mMasterKeyId);
|
||||||
|
startActivityForResult(certifyIntent, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(ImportKeyResult result) {
|
||||||
|
Bundle returnData = new Bundle();
|
||||||
|
returnData.putParcelable(OperationResult.EXTRA_RESULT, result);
|
||||||
|
Intent data = new Intent();
|
||||||
|
data.putExtras(returnData);
|
||||||
|
setResult(RESULT_OK, data);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,9 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.support.v4.app.NavUtils;
|
import android.support.v4.app.NavUtils;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -33,23 +30,30 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the selected public key to a keyserver
|
* Sends the selected public key to a keyserver
|
||||||
*/
|
*/
|
||||||
public class UploadKeyActivity extends BaseActivity {
|
public class UploadKeyActivity extends BaseActivity
|
||||||
|
implements CryptoOperationHelper.Callback<ExportKeyringParcel, ExportResult> {
|
||||||
private View mUploadButton;
|
private View mUploadButton;
|
||||||
private Spinner mKeyServerSpinner;
|
private Spinner mKeyServerSpinner;
|
||||||
|
|
||||||
private Uri mDataUri;
|
private Uri mDataUri;
|
||||||
|
|
||||||
|
// CryptoOperationHelper.Callback vars
|
||||||
|
private String mKeyserver;
|
||||||
|
private Uri mUnifiedKeyringUri;
|
||||||
|
private CryptoOperationHelper<ExportKeyringParcel, ExportResult> mUploadOpHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -89,51 +93,23 @@ public class UploadKeyActivity extends BaseActivity {
|
|||||||
setContentView(R.layout.upload_key_activity);
|
setContentView(R.layout.upload_key_activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (mUploadOpHelper != null) {
|
||||||
|
mUploadOpHelper.handleActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
private void uploadKey() {
|
private void uploadKey() {
|
||||||
// Send all information needed to service to upload key in other thread
|
|
||||||
Intent intent = new Intent(this, KeychainService.class);
|
|
||||||
|
|
||||||
intent.setAction(KeychainService.ACTION_UPLOAD_KEYRING);
|
|
||||||
|
|
||||||
// set data uri as path to keyring
|
|
||||||
Uri blobUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
|
Uri blobUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
|
||||||
intent.setData(blobUri);
|
mUnifiedKeyringUri = blobUri;
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
|
|
||||||
String server = (String) mKeyServerSpinner.getSelectedItem();
|
String server = (String) mKeyServerSpinner.getSelectedItem();
|
||||||
data.putString(KeychainService.UPLOAD_KEY_SERVER, server);
|
mKeyserver = server;
|
||||||
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
mUploadOpHelper = new CryptoOperationHelper(this, this, R.string.progress_uploading);
|
||||||
|
mUploadOpHelper.cryptoOperation();
|
||||||
// Message is received after uploading 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()) {
|
|
||||||
|
|
||||||
Toast.makeText(UploadKeyActivity.this, R.string.msg_crt_upload_success,
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(saveHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// show progress dialog
|
|
||||||
saveHandler.showProgressDialog(
|
|
||||||
getString(R.string.progress_uploading),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, false);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
startService(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -148,4 +124,30 @@ public class UploadKeyActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExportKeyringParcel createOperationInput() {
|
||||||
|
return new ExportKeyringParcel(mKeyserver, mUnifiedKeyringUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(ExportResult result) {
|
||||||
|
Toast.makeText(UploadKeyActivity.this, R.string.msg_crt_upload_success,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(ExportResult result) {
|
||||||
|
// TODO: Implement proper log for key upload then show error
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,11 +65,13 @@ import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
|||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
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.KeychainService;
|
import org.sufficientlysecure.keychain.service.KeychainService;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
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.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.dialog.DeleteKeyDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||||
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;
|
||||||
@@ -89,7 +91,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class ViewKeyActivity extends BaseNfcActivity implements
|
public class ViewKeyActivity extends BaseNfcActivity implements
|
||||||
LoaderManager.LoaderCallbacks<Cursor> {
|
LoaderManager.LoaderCallbacks<Cursor>,
|
||||||
|
CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> {
|
||||||
|
|
||||||
public static final String EXTRA_NFC_USER_ID = "nfc_user_id";
|
public static final String EXTRA_NFC_USER_ID = "nfc_user_id";
|
||||||
public static final String EXTRA_NFC_AID = "nfc_aid";
|
public static final String EXTRA_NFC_AID = "nfc_aid";
|
||||||
@@ -105,6 +108,11 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
|||||||
|
|
||||||
protected Uri mDataUri;
|
protected Uri mDataUri;
|
||||||
|
|
||||||
|
// For CryptoOperationHelper.Callback
|
||||||
|
private String mKeyserver;
|
||||||
|
private ArrayList<ParcelableKeyRing> mKeyList;
|
||||||
|
private CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult> mOperationHelper;
|
||||||
|
|
||||||
private TextView mName;
|
private TextView mName;
|
||||||
private TextView mStatusText;
|
private TextView mStatusText;
|
||||||
private ImageView mStatusImage;
|
private ImageView mStatusImage;
|
||||||
@@ -396,7 +404,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
|||||||
|
|
||||||
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);
|
startCertifyIntent(intent);
|
||||||
}
|
}
|
||||||
@@ -486,6 +494,10 @@ 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) {
|
||||||
|
mOperationHelper.handleActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
if (requestCode == REQUEST_QR_FINGERPRINT && resultCode == Activity.RESULT_OK) {
|
if (requestCode == REQUEST_QR_FINGERPRINT && resultCode == Activity.RESULT_OK) {
|
||||||
|
|
||||||
// If there is an EXTRA_RESULT, that's an error. Just show it.
|
// If there is an EXTRA_RESULT, that's an error. Just show it.
|
||||||
@@ -651,56 +663,20 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
|||||||
ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null);
|
ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null);
|
||||||
ArrayList<ParcelableKeyRing> entries = new ArrayList<>();
|
ArrayList<ParcelableKeyRing> entries = new ArrayList<>();
|
||||||
entries.add(keyEntry);
|
entries.add(keyEntry);
|
||||||
|
mKeyList = entries;
|
||||||
// Message is received after importing is done in KeychainService
|
|
||||||
ServiceProgressHandler serviceHandler = new ServiceProgressHandler(this) {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
|
||||||
super.handleMessage(message);
|
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
// get returned data bundle
|
|
||||||
Bundle returnData = message.getData();
|
|
||||||
|
|
||||||
mIsRefreshing = false;
|
|
||||||
|
|
||||||
if (returnData == null) {
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final ImportKeyResult result =
|
|
||||||
returnData.getParcelable(OperationResult.EXTRA_RESULT);
|
|
||||||
result.createNotify(ViewKeyActivity.this).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
|
|
||||||
// search config
|
// search config
|
||||||
{
|
{
|
||||||
Preferences prefs = Preferences.getPreferences(this);
|
Preferences prefs = Preferences.getPreferences(this);
|
||||||
Preferences.CloudSearchPrefs cloudPrefs =
|
Preferences.CloudSearchPrefs cloudPrefs =
|
||||||
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
||||||
data.putString(KeychainService.IMPORT_KEY_SERVER, cloudPrefs.keyserver);
|
mKeyserver = cloudPrefs.keyserver;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.putParcelableArrayList(KeychainService.IMPORT_KEY_LIST, entries);
|
mOperationHelper = new CryptoOperationHelper<>(
|
||||||
|
this, this, R.string.progress_importing);
|
||||||
// Send all information needed to service to query keys in other thread
|
|
||||||
Intent intent = new Intent(this, KeychainService.class);
|
|
||||||
intent.setAction(KeychainService.ACTION_IMPORT_KEYRING);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(serviceHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
startService(intent);
|
|
||||||
|
|
||||||
|
mOperationHelper.cryptoOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void editKey(Uri dataUri) {
|
private void editKey(Uri dataUri) {
|
||||||
@@ -986,4 +962,33 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
|||||||
public void onLoaderReset(Loader<Cursor> loader) {
|
public void onLoaderReset(Loader<Cursor> loader) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CryptoOperationHelper.Callback functions
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImportKeyringParcel createOperationInput() {
|
||||||
|
return new ImportKeyringParcel(mKeyList, mKeyserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(ImportKeyResult result) {
|
||||||
|
mIsRefreshing = false;
|
||||||
|
result.createNotify(this).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
mIsRefreshing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(ImportKeyResult result) {
|
||||||
|
mIsRefreshing = false;
|
||||||
|
result.createNotify(this).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -17,15 +17,12 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
@@ -48,9 +45,10 @@ import com.textuality.keybase.lib.User;
|
|||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.KeybaseVerificationResult;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
@@ -59,7 +57,8 @@ import java.util.Hashtable;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ViewKeyTrustFragment extends LoaderFragment implements
|
public class ViewKeyTrustFragment extends LoaderFragment implements
|
||||||
LoaderManager.LoaderCallbacks<Cursor> {
|
LoaderManager.LoaderCallbacks<Cursor>,
|
||||||
|
CryptoOperationHelper.Callback<KeybaseVerificationParcel, KeybaseVerificationResult> {
|
||||||
|
|
||||||
public static final String ARG_DATA_URI = "uri";
|
public static final String ARG_DATA_URI = "uri";
|
||||||
|
|
||||||
@@ -76,6 +75,14 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
|
|||||||
// for retrieving the key we’re working on
|
// for retrieving the key we’re working on
|
||||||
private Uri mDataUri;
|
private Uri mDataUri;
|
||||||
|
|
||||||
|
private Proof mProof;
|
||||||
|
|
||||||
|
// for CryptoOperationHelper,Callback
|
||||||
|
private String mKeybaseProof;
|
||||||
|
private String mKeybaseFingerprint;
|
||||||
|
private CryptoOperationHelper<KeybaseVerificationParcel, KeybaseVerificationResult>
|
||||||
|
mKeybaseOpHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
|
||||||
View root = super.onCreateView(inflater, superContainer, savedInstanceState);
|
View root = super.onCreateView(inflater, superContainer, savedInstanceState);
|
||||||
@@ -349,34 +356,42 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void verify(final Proof proof, final String fingerprint) {
|
private void verify(final Proof proof, final String fingerprint) {
|
||||||
Intent intent = new Intent(getActivity(), KeychainService.class);
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
intent.setAction(KeychainService.ACTION_VERIFY_KEYBASE_PROOF);
|
|
||||||
|
|
||||||
data.putString(KeychainService.KEYBASE_PROOF, proof.toString());
|
mProof = proof;
|
||||||
data.putString(KeychainService.KEYBASE_REQUIRED_FINGERPRINT, fingerprint);
|
mKeybaseProof = proof.toString();
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
mKeybaseFingerprint = fingerprint;
|
||||||
|
|
||||||
mProofVerifyDetail.setVisibility(View.GONE);
|
mProofVerifyDetail.setVisibility(View.GONE);
|
||||||
|
|
||||||
// Create a new Messenger for the communication back after proof work is done
|
mKeybaseOpHelper = new CryptoOperationHelper<>(this, this,
|
||||||
ServiceProgressHandler handler = new ServiceProgressHandler(getActivity()) {
|
R.string.progress_verifying_signature);
|
||||||
|
mKeybaseOpHelper.cryptoOperation();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message message) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
super.handleMessage(message);
|
if (mKeybaseOpHelper != null) {
|
||||||
|
mKeybaseOpHelper.handleActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
// CryptoOperationHelper.Callback methods
|
||||||
Bundle returnData = message.getData();
|
@Override
|
||||||
String msg = returnData.getString(ServiceProgressHandler.DATA_MESSAGE);
|
public KeybaseVerificationParcel createOperationInput() {
|
||||||
SpannableStringBuilder ssb = new SpannableStringBuilder();
|
return new KeybaseVerificationParcel(mKeybaseProof, mKeybaseFingerprint);
|
||||||
|
}
|
||||||
|
|
||||||
if ((msg != null) && msg.equals("OK")) {
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(KeybaseVerificationResult result) {
|
||||||
|
|
||||||
//yay
|
result.createNotify(getActivity()).show();
|
||||||
String proofUrl = returnData.getString(ServiceProgressHandler.KEYBASE_PROOF_URL);
|
|
||||||
String presenceUrl = returnData.getString(ServiceProgressHandler.KEYBASE_PRESENCE_URL);
|
String proofUrl = result.mProofUrl;
|
||||||
String presenceLabel = returnData.getString(ServiceProgressHandler.KEYBASE_PRESENCE_LABEL);
|
String presenceUrl = result.mPresenceUrl;
|
||||||
|
String presenceLabel = result.mPresenceLabel;
|
||||||
|
|
||||||
|
Proof proof = mProof; // TODO: should ideally be contained in result
|
||||||
|
|
||||||
String proofLabel;
|
String proofLabel;
|
||||||
switch (proof.getType()) {
|
switch (proof.getType()) {
|
||||||
@@ -400,6 +415,8 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpannableStringBuilder ssb = new SpannableStringBuilder();
|
||||||
|
|
||||||
ssb.append(getString(R.string.keybase_proof_succeeded));
|
ssb.append(getString(R.string.keybase_proof_succeeded));
|
||||||
StyleSpan bold = new StyleSpan(Typeface.BOLD);
|
StyleSpan bold = new StyleSpan(Typeface.BOLD);
|
||||||
ssb.setSpan(bold, 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
ssb.setSpan(bold, 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
@@ -418,43 +435,51 @@ public class ViewKeyTrustFragment extends LoaderFragment implements
|
|||||||
length = ssb.length();
|
length = ssb.length();
|
||||||
URLSpan presenceLink = new URLSpan(presenceUrl);
|
URLSpan presenceLink = new URLSpan(presenceUrl);
|
||||||
ssb.append(presenceLabel);
|
ssb.append(presenceLabel);
|
||||||
ssb.setSpan(presenceLink, length, length + presenceLabel.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
ssb.setSpan(presenceLink, length, length + presenceLabel.length(), Spanned
|
||||||
|
.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
if (Proof.PROOF_TYPE_REDDIT == proof.getType()) {
|
if (Proof.PROOF_TYPE_REDDIT == proof.getType()) {
|
||||||
ssb.append(", ").
|
ssb.append(", ").
|
||||||
append(getString(R.string.keybase_reddit_attribution)).
|
append(getString(R.string.keybase_reddit_attribution)).
|
||||||
append(" “").append(proof.getHandle()).append("”, ");
|
append(" “").append(proof.getHandle()).append("”, ");
|
||||||
}
|
}
|
||||||
ssb.append(" ").append(getString(R.string.keybase_contained_signature));
|
ssb.append(" ").append(getString(R.string.keybase_contained_signature));
|
||||||
} else {
|
|
||||||
// verification failed!
|
displaySpannableResult(ssb);
|
||||||
msg = returnData.getString(ServiceProgressHandler.DATA_ERROR);
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(KeybaseVerificationResult result) {
|
||||||
|
|
||||||
|
result.createNotify(getActivity()).show();
|
||||||
|
|
||||||
|
SpannableStringBuilder ssb = new SpannableStringBuilder();
|
||||||
|
|
||||||
ssb.append(getString(R.string.keybase_proof_failure));
|
ssb.append(getString(R.string.keybase_proof_failure));
|
||||||
|
String msg = getString(result.getLog().getLast().mType.mMsgId);
|
||||||
if (msg == null) {
|
if (msg == null) {
|
||||||
msg = getString(R.string.keybase_unknown_proof_failure);
|
msg = getString(R.string.keybase_unknown_proof_failure);
|
||||||
}
|
}
|
||||||
StyleSpan bold = new StyleSpan(Typeface.BOLD);
|
StyleSpan bold = new StyleSpan(Typeface.BOLD);
|
||||||
ssb.setSpan(bold, 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
ssb.setSpan(bold, 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
ssb.append("\n\n").append(msg);
|
ssb.append("\n\n").append(msg);
|
||||||
|
|
||||||
|
displaySpannableResult(ssb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displaySpannableResult(SpannableStringBuilder ssb) {
|
||||||
mProofVerifyHeader.setVisibility(View.VISIBLE);
|
mProofVerifyHeader.setVisibility(View.VISIBLE);
|
||||||
mProofVerifyDetail.setVisibility(View.VISIBLE);
|
mProofVerifyDetail.setVisibility(View.VISIBLE);
|
||||||
mProofVerifyDetail.setMovementMethod(LinkMovementMethod.getInstance());
|
mProofVerifyDetail.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
mProofVerifyDetail.setText(ssb);
|
mProofVerifyDetail.setText(ssb);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(handler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// show progress dialog
|
|
||||||
handler.showProgressDialog(
|
|
||||||
getString(R.string.progress_verifying_signature),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, false
|
|
||||||
);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
getActivity().startService(intent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,8 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
@@ -39,16 +35,16 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
|
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.KeychainService;
|
import org.sufficientlysecure.keychain.service.PromoteKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
|
||||||
|
|
||||||
public class ViewKeyYubiKeyFragment extends Fragment
|
public class ViewKeyYubiKeyFragment
|
||||||
|
extends CryptoOperationFragment<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";
|
||||||
@@ -60,6 +56,8 @@ public class ViewKeyYubiKeyFragment extends Fragment
|
|||||||
private String mUserId;
|
private String mUserId;
|
||||||
private byte[] mCardAid;
|
private byte[] mCardAid;
|
||||||
private long mMasterKeyId;
|
private long mMasterKeyId;
|
||||||
|
private long[] mSubKeyIds;
|
||||||
|
|
||||||
private Button vButton;
|
private Button vButton;
|
||||||
private TextView vStatus;
|
private TextView vStatus;
|
||||||
|
|
||||||
@@ -127,50 +125,15 @@ public class ViewKeyYubiKeyFragment extends Fragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void promoteToSecretKey() {
|
public void promoteToSecretKey() {
|
||||||
|
|
||||||
ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
|
||||||
super.handleMessage(message);
|
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
// get returned data bundle
|
|
||||||
Bundle returnData = message.getData();
|
|
||||||
|
|
||||||
PromoteKeyResult result =
|
|
||||||
returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT);
|
|
||||||
|
|
||||||
result.createNotify(getActivity()).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send all information needed to service to decrypt in other thread
|
|
||||||
Intent intent = new Intent(getActivity(), KeychainService.class);
|
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
|
|
||||||
intent.setAction(KeychainService.ACTION_PROMOTE_KEYRING);
|
|
||||||
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
data.putLong(KeychainService.PROMOTE_MASTER_KEY_ID, mMasterKeyId);
|
|
||||||
data.putByteArray(KeychainService.PROMOTE_CARD_AID, mCardAid);
|
|
||||||
long[] subKeyIds = new long[mFingerprints.length];
|
long[] subKeyIds = new long[mFingerprints.length];
|
||||||
for (int i = 0; i < subKeyIds.length; i++) {
|
for (int i = 0; i < subKeyIds.length; i++) {
|
||||||
subKeyIds[i] = KeyFormattingUtils.getKeyIdFromFingerprint(mFingerprints[i]);
|
subKeyIds[i] = KeyFormattingUtils.getKeyIdFromFingerprint(mFingerprints[i]);
|
||||||
}
|
}
|
||||||
data.putLongArray(KeychainService.PROMOTE_SUBKEY_IDS, subKeyIds);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
// mMasterKeyId and mCardAid are already set
|
||||||
Messenger messenger = new Messenger(saveHandler);
|
mSubKeyIds = subKeyIds;
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
getActivity().startService(intent);
|
|
||||||
|
|
||||||
|
cryptoOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String[] PROJECTION = new String[]{
|
public static final String[] PROJECTION = new String[]{
|
||||||
@@ -240,4 +203,14 @@ public class ViewKeyYubiKeyFragment extends Fragment
|
|||||||
public void onLoaderReset(Loader<Cursor> loader) {
|
public void onLoaderReset(Loader<Cursor> loader) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PromoteKeyringParcel createOperationInput() {
|
||||||
|
return new PromoteKeyringParcel(mMasterKeyId, mCardAid, mSubKeyIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCryptoOperationResult(PromoteKeyResult result) {
|
||||||
|
result.createNotify(getActivity()).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
|
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
|
||||||
|
import org.sufficientlysecure.keychain.operations.ImportOperation;
|
||||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||||
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;
|
||||||
@@ -92,8 +93,8 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 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 ImportExportOperation for specifics.
|
* before secret keys, see ImportOperation for specifics.
|
||||||
* @see org.sufficientlysecure.keychain.operations.ImportExportOperation
|
* @see ImportOperation
|
||||||
*/
|
*/
|
||||||
public ArrayList<ImportKeysListEntry> getSelectedEntries() {
|
public ArrayList<ImportKeysListEntry> getSelectedEntries() {
|
||||||
ArrayList<ImportKeysListEntry> result = new ArrayList<>();
|
ArrayList<ImportKeysListEntry> result = new ArrayList<>();
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ public abstract class CachingCryptoOperationFragment <T extends Parcelable, S ex
|
|||||||
mCachedActionsParcel = null;
|
mCachedActionsParcel = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract T createOperationInput();
|
@Override
|
||||||
|
public abstract T createOperationInput();
|
||||||
|
|
||||||
protected T getCachedActionsParcel() {
|
protected T getCachedActionsParcel() {
|
||||||
return mCachedActionsParcel;
|
return mCachedActionsParcel;
|
||||||
@@ -46,7 +47,7 @@ public abstract class CachingCryptoOperationFragment <T extends Parcelable, S ex
|
|||||||
mCachedActionsParcel = cachedActionsParcel;
|
mCachedActionsParcel = cachedActionsParcel;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onCryptoOperationCancelled() {
|
public void onCryptoOperationCancelled() {
|
||||||
mCachedActionsParcel = null;
|
mCachedActionsParcel = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,217 +18,78 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui.base;
|
package org.sufficientlysecure.keychain.ui.base;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainNewService;
|
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
|
||||||
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.ui.NfcOperationActivity;
|
|
||||||
import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
|
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All fragments executing crypto operations need to extend this class.
|
* All fragments executing crypto operations need to extend this class.
|
||||||
*/
|
*/
|
||||||
public abstract class CryptoOperationFragment <T extends Parcelable, S extends OperationResult>
|
public abstract class CryptoOperationFragment<T extends Parcelable, S extends OperationResult>
|
||||||
extends Fragment {
|
extends Fragment implements CryptoOperationHelper.Callback<T, S> {
|
||||||
|
|
||||||
public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
|
private CryptoOperationHelper<T, S> mOperationHelper;
|
||||||
public static final int REQUEST_CODE_NFC = 0x00008002;
|
|
||||||
|
|
||||||
private void initiateInputActivity(RequiredInputParcel requiredInput) {
|
public CryptoOperationFragment() {
|
||||||
|
|
||||||
switch (requiredInput.mType) {
|
mOperationHelper = new CryptoOperationHelper<>(this, this);
|
||||||
case NFC_MOVE_KEY_TO_CARD:
|
|
||||||
case NFC_DECRYPT:
|
|
||||||
case NFC_SIGN: {
|
|
||||||
Intent intent = new Intent(getActivity(), NfcOperationActivity.class);
|
|
||||||
intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput);
|
|
||||||
startActivityForResult(intent, REQUEST_CODE_NFC);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case PASSPHRASE:
|
public void setProgressMessageResource(int id) {
|
||||||
case PASSPHRASE_SYMMETRIC: {
|
mOperationHelper.setProgressMessageResource(id);
|
||||||
Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
|
|
||||||
intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput);
|
|
||||||
startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new RuntimeException("Unhandled pending result!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
if (resultCode == Activity.RESULT_CANCELED) {
|
mOperationHelper.handleActivityResult(requestCode, resultCode, data);
|
||||||
onCryptoOperationCancelled();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (requestCode) {
|
@Override
|
||||||
case REQUEST_CODE_PASSPHRASE: {
|
public abstract T createOperationInput();
|
||||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
|
||||||
CryptoInputParcel cryptoInput =
|
|
||||||
data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT);
|
|
||||||
cryptoOperation(cryptoInput);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case REQUEST_CODE_NFC: {
|
|
||||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
|
||||||
CryptoInputParcel cryptoInput =
|
|
||||||
data.getParcelableExtra(NfcOperationActivity.RESULT_DATA);
|
|
||||||
cryptoOperation(cryptoInput);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void dismissProgress() {
|
|
||||||
|
|
||||||
ProgressDialogFragment progressDialogFragment =
|
|
||||||
(ProgressDialogFragment) getFragmentManager().findFragmentByTag("progressDialog");
|
|
||||||
|
|
||||||
if (progressDialogFragment == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
progressDialogFragment.dismissAllowingStateLoss();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract T createOperationInput();
|
|
||||||
|
|
||||||
protected void cryptoOperation(CryptoInputParcel cryptoInput) {
|
|
||||||
cryptoOperation(cryptoInput, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void cryptoOperation() {
|
protected void cryptoOperation() {
|
||||||
cryptoOperation(new CryptoInputParcel());
|
cryptoOperation(new CryptoInputParcel());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void cryptoOperation(CryptoInputParcel cryptoInput) {
|
||||||
|
cryptoOperation(cryptoInput);
|
||||||
|
}
|
||||||
|
|
||||||
protected void cryptoOperation(CryptoInputParcel cryptoInput, boolean showProgress) {
|
protected void cryptoOperation(CryptoInputParcel cryptoInput, boolean showProgress) {
|
||||||
|
mOperationHelper.cryptoOperation(cryptoInput, showProgress);
|
||||||
T operationInput = createOperationInput();
|
|
||||||
if (operationInput == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send all information needed to service to edit key in other thread
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
Intent intent = new Intent(getActivity(), KeychainNewService.class);
|
|
||||||
|
|
||||||
intent.putExtra(KeychainNewService.EXTRA_OPERATION_INPUT, operationInput);
|
|
||||||
intent.putExtra(KeychainNewService.EXTRA_CRYPTO_INPUT, cryptoInput);
|
|
||||||
|
|
||||||
ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
|
||||||
super.handleMessage(message);
|
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
|
|
||||||
// get returned data bundle
|
|
||||||
Bundle returnData = message.getData();
|
|
||||||
if (returnData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final OperationResult result =
|
|
||||||
returnData.getParcelable(OperationResult.EXTRA_RESULT);
|
|
||||||
|
|
||||||
onHandleResult(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSetProgress(String msg, int progress, int max) {
|
|
||||||
// allow handling of progress in fragment, or delegate upwards
|
|
||||||
if ( ! onCryptoSetProgress(msg, progress, max)) {
|
|
||||||
super.onSetProgress(msg, progress, max);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(saveHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
if (showProgress) {
|
|
||||||
saveHandler.showProgressDialog(
|
|
||||||
getString(R.string.progress_building_key),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
getActivity().startService(intent);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onCryptoOperationResult(S result) {
|
|
||||||
if (result.success()) {
|
|
||||||
onCryptoOperationSuccess(result);
|
|
||||||
} else {
|
|
||||||
onCryptoOperationError(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract protected void onCryptoOperationSuccess(S result);
|
|
||||||
|
|
||||||
protected void onCryptoOperationError(S result) {
|
|
||||||
result.createNotify(getActivity()).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onCryptoOperationCancelled() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onHandleResult(OperationResult result) {
|
|
||||||
|
|
||||||
if (result instanceof InputPendingResult) {
|
|
||||||
InputPendingResult pendingResult = (InputPendingResult) result;
|
|
||||||
if (pendingResult.isPending()) {
|
|
||||||
RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel();
|
|
||||||
initiateInputActivity(requiredInput);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dismissProgress();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// noinspection unchecked, because type erasure :(
|
|
||||||
onCryptoOperationResult((S) result);
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
throw new AssertionError("bad return class ("
|
|
||||||
+ result.getClass().getSimpleName() + "), this is a programming error!");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean onCryptoSetProgress(String msg, int progress, int max) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(S result) {
|
||||||
|
onCryptoOperationResult(result);
|
||||||
|
result.createNotify(getActivity()).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(S result) {
|
||||||
|
onCryptoOperationResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* To be overriden by subclasses, if desired. Provides a way to access the method by the
|
||||||
|
* same name in CryptoOperationHelper, if super.onCryptoOperationSuccess and
|
||||||
|
* super.onCryptoOperationError are called at the start of the respective functions in the
|
||||||
|
* subclass overriding them
|
||||||
|
* @param result
|
||||||
|
*/
|
||||||
|
protected void onCryptoOperationResult(S result) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,326 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
* Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
|
||||||
|
* Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui.base;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.os.Messenger;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
|
||||||
|
import android.support.v4.app.FragmentManager;
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeychainService;
|
||||||
|
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
||||||
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||||
|
import org.sufficientlysecure.keychain.ui.NfcOperationActivity;
|
||||||
|
import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
|
||||||
|
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Designed to be integrated into activities or fragments used for CryptoOperations.
|
||||||
|
* Encapsulates the execution of a crypto operation and handling of input pending cases.s
|
||||||
|
*
|
||||||
|
* @param <T> The type of input parcel sent to the operation
|
||||||
|
* @param <S> The type of result returned by the operation
|
||||||
|
*/
|
||||||
|
public class CryptoOperationHelper<T extends Parcelable, S extends OperationResult> {
|
||||||
|
|
||||||
|
public interface Callback <T extends Parcelable, S extends OperationResult> {
|
||||||
|
T createOperationInput();
|
||||||
|
void onCryptoOperationSuccess(S result);
|
||||||
|
void onCryptoOperationCancelled();
|
||||||
|
void onCryptoOperationError(S result);
|
||||||
|
boolean onCryptoSetProgress(String msg, int progress, int max);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
|
||||||
|
public static final int REQUEST_CODE_NFC = 0x00008002;
|
||||||
|
|
||||||
|
// keeps track of request code used to start an activity from this CryptoOperationHelper.
|
||||||
|
// this is necessary when multiple CryptoOperationHelpers are used in the same fragment/activity
|
||||||
|
// otherwise all CryptoOperationHandlers may respond to the same onActivityResult
|
||||||
|
private int mRequestedCode = -1;
|
||||||
|
|
||||||
|
private int mProgressMessageResource;
|
||||||
|
|
||||||
|
private FragmentActivity mActivity;
|
||||||
|
private Fragment mFragment;
|
||||||
|
private Callback<T, S> mCallback;
|
||||||
|
|
||||||
|
private boolean mUseFragment; // short hand for mActivity == null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If OperationHelper is being integrated into an activity
|
||||||
|
*
|
||||||
|
* @param activity
|
||||||
|
*/
|
||||||
|
public CryptoOperationHelper(FragmentActivity activity, Callback<T, S> callback, int progressMessageString) {
|
||||||
|
mActivity = activity;
|
||||||
|
mUseFragment = false;
|
||||||
|
mCallback = callback;
|
||||||
|
mProgressMessageResource = progressMessageString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if OperationHelper is being integrated into a fragment
|
||||||
|
*
|
||||||
|
* @param fragment
|
||||||
|
*/
|
||||||
|
public CryptoOperationHelper(Fragment fragment, Callback<T, S> callback, int progressMessageString) {
|
||||||
|
mFragment = fragment;
|
||||||
|
mUseFragment = true;
|
||||||
|
mProgressMessageResource = progressMessageString;
|
||||||
|
mCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if OperationHelper is being integrated into a fragment with default message for the progress dialog
|
||||||
|
*
|
||||||
|
* @param fragment
|
||||||
|
*/
|
||||||
|
public CryptoOperationHelper(Fragment fragment, Callback<T, S> callback) {
|
||||||
|
mFragment = fragment;
|
||||||
|
mUseFragment = true;
|
||||||
|
mProgressMessageResource = R.string.progress_building_key;
|
||||||
|
mCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProgressMessageResource(int id) {
|
||||||
|
mProgressMessageResource = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initiateInputActivity(RequiredInputParcel requiredInput) {
|
||||||
|
|
||||||
|
Activity activity = mUseFragment ? mFragment.getActivity() : mActivity;
|
||||||
|
|
||||||
|
switch (requiredInput.mType) {
|
||||||
|
case NFC_MOVE_KEY_TO_CARD:
|
||||||
|
case NFC_DECRYPT:
|
||||||
|
case NFC_SIGN: {
|
||||||
|
Intent intent = new Intent(activity, NfcOperationActivity.class);
|
||||||
|
intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput);
|
||||||
|
mRequestedCode = REQUEST_CODE_NFC;
|
||||||
|
if (mUseFragment) {
|
||||||
|
mFragment.startActivityForResult(intent, mRequestedCode);
|
||||||
|
} else {
|
||||||
|
mActivity.startActivityForResult(intent, mRequestedCode);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PASSPHRASE:
|
||||||
|
case PASSPHRASE_SYMMETRIC: {
|
||||||
|
Intent intent = new Intent(activity, PassphraseDialogActivity.class);
|
||||||
|
intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput);
|
||||||
|
mRequestedCode = REQUEST_CODE_PASSPHRASE;
|
||||||
|
if (mUseFragment) {
|
||||||
|
mFragment.startActivityForResult(intent, mRequestedCode);
|
||||||
|
} else {
|
||||||
|
mActivity.startActivityForResult(intent, mRequestedCode);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException("Unhandled pending result!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts the result of an activity started by this helper. Returns true if requestCode is recognized,
|
||||||
|
* false otherwise.
|
||||||
|
*
|
||||||
|
* @param requestCode
|
||||||
|
* @param resultCode
|
||||||
|
* @param data
|
||||||
|
* @return true if requestCode was recognized, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean handleActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
Log.d(Constants.TAG, "received activity result in OperationHelper");
|
||||||
|
|
||||||
|
if (mRequestedCode != requestCode) {
|
||||||
|
// this wasn't meant for us to handle
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
mRequestedCode = -1;
|
||||||
|
}
|
||||||
|
if (resultCode == Activity.RESULT_CANCELED) {
|
||||||
|
mCallback.onCryptoOperationCancelled();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (requestCode) {
|
||||||
|
case REQUEST_CODE_PASSPHRASE: {
|
||||||
|
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||||
|
CryptoInputParcel cryptoInput =
|
||||||
|
data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT);
|
||||||
|
cryptoOperation(cryptoInput);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case REQUEST_CODE_NFC: {
|
||||||
|
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||||
|
CryptoInputParcel cryptoInput =
|
||||||
|
data.getParcelableExtra(NfcOperationActivity.RESULT_DATA);
|
||||||
|
cryptoOperation(cryptoInput);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void dismissProgress() {
|
||||||
|
FragmentManager fragmentManager =
|
||||||
|
mUseFragment ? mFragment.getFragmentManager() :
|
||||||
|
mActivity.getSupportFragmentManager();
|
||||||
|
|
||||||
|
if (fragmentManager == null) { // the fragment holding us has died
|
||||||
|
// fragmentManager was null when used with DialogFragments. (they close on click?)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressDialogFragment progressDialogFragment =
|
||||||
|
(ProgressDialogFragment) fragmentManager.findFragmentByTag(
|
||||||
|
ServiceProgressHandler.TAG_PROGRESS_DIALOG);
|
||||||
|
|
||||||
|
if (progressDialogFragment == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
progressDialogFragment.dismissAllowingStateLoss();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cryptoOperation(CryptoInputParcel cryptoInput, boolean showProgress) {
|
||||||
|
|
||||||
|
FragmentActivity activity = mUseFragment ? mFragment.getActivity() : mActivity;
|
||||||
|
|
||||||
|
T operationInput = mCallback.createOperationInput();
|
||||||
|
if (operationInput == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send all information needed to service to edit key in other thread
|
||||||
|
Intent intent = new Intent(activity, KeychainService.class);
|
||||||
|
|
||||||
|
intent.putExtra(KeychainService.EXTRA_OPERATION_INPUT, operationInput);
|
||||||
|
intent.putExtra(KeychainService.EXTRA_CRYPTO_INPUT, cryptoInput);
|
||||||
|
|
||||||
|
ServiceProgressHandler saveHandler = new ServiceProgressHandler(activity) {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
// handle messages by standard KeychainIntentServiceHandler first
|
||||||
|
super.handleMessage(message);
|
||||||
|
|
||||||
|
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||||
|
|
||||||
|
// get returned data bundle
|
||||||
|
Bundle returnData = message.getData();
|
||||||
|
if (returnData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final OperationResult result =
|
||||||
|
returnData.getParcelable(OperationResult.EXTRA_RESULT);
|
||||||
|
|
||||||
|
onHandleResult(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSetProgress(String msg, int progress, int max) {
|
||||||
|
// allow handling of progress in fragment, or delegate upwards
|
||||||
|
if ( ! mCallback.onCryptoSetProgress(msg, progress, max)) {
|
||||||
|
super.onSetProgress(msg, progress, max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a new Messenger for the communication back
|
||||||
|
Messenger messenger = new Messenger(saveHandler);
|
||||||
|
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
||||||
|
|
||||||
|
if (showProgress) {
|
||||||
|
saveHandler.showProgressDialog(
|
||||||
|
activity.getString(mProgressMessageResource),
|
||||||
|
ProgressDialog.STYLE_HORIZONTAL, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
activity.startService(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cryptoOperation(CryptoInputParcel cryptoInputParcel) {
|
||||||
|
cryptoOperation(cryptoInputParcel, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cryptoOperation() {
|
||||||
|
cryptoOperation(new CryptoInputParcel());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onCryptoOperationResult(S result) {
|
||||||
|
if (result.success()) {
|
||||||
|
mCallback.onCryptoOperationSuccess(result);
|
||||||
|
} else {
|
||||||
|
mCallback.onCryptoOperationError(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onHandleResult(OperationResult result) {
|
||||||
|
Log.d(Constants.TAG, "Handling result in OperationHelper success: " + result.success());
|
||||||
|
|
||||||
|
if (result instanceof InputPendingResult) {
|
||||||
|
InputPendingResult pendingResult = (InputPendingResult) result;
|
||||||
|
if (pendingResult.isPending()) {
|
||||||
|
|
||||||
|
RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel();
|
||||||
|
initiateInputActivity(requiredInput);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dismissProgress();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// noinspection unchecked, because type erasure :(
|
||||||
|
onCryptoOperationResult((S) result);
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new AssertionError("bad return class ("
|
||||||
|
+ result.getClass().getSimpleName() + "), this is a programming error!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
package org.sufficientlysecure.keychain.ui.dialog;
|
package org.sufficientlysecure.keychain.ui.dialog;
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -33,16 +32,20 @@ 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.operations.results.DeleteResult;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||||
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.KeychainService;
|
import org.sufficientlysecure.keychain.service.DeleteKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
||||||
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class DeleteKeyDialogFragment extends DialogFragment {
|
public class DeleteKeyDialogFragment extends DialogFragment
|
||||||
|
implements CryptoOperationHelper.Callback<DeleteKeyringParcel, DeleteResult> {
|
||||||
private static final String ARG_MESSENGER = "messenger";
|
private static final String ARG_MESSENGER = "messenger";
|
||||||
private static final String ARG_DELETE_MASTER_KEY_IDS = "delete_master_key_ids";
|
private static final String ARG_DELETE_MASTER_KEY_IDS = "delete_master_key_ids";
|
||||||
|
|
||||||
@@ -52,6 +55,13 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
|||||||
private TextView mMainMessage;
|
private TextView mMainMessage;
|
||||||
private View mInflateView;
|
private View mInflateView;
|
||||||
|
|
||||||
|
private Messenger mMessenger;
|
||||||
|
|
||||||
|
// for CryptoOperationHelper.Callback
|
||||||
|
private long[] mMasterKeyIds;
|
||||||
|
private boolean mHasSecret;
|
||||||
|
private CryptoOperationHelper<DeleteKeyringParcel, DeleteResult> mDeleteOpHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new instance of this delete file dialog fragment
|
* Creates new instance of this delete file dialog fragment
|
||||||
*/
|
*/
|
||||||
@@ -67,10 +77,18 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
|||||||
return frag;
|
return frag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (mDeleteOpHelper != null) {
|
||||||
|
mDeleteOpHelper.handleActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
final FragmentActivity activity = getActivity();
|
final FragmentActivity activity = getActivity();
|
||||||
final Messenger messenger = getArguments().getParcelable(ARG_MESSENGER);
|
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
|
||||||
|
|
||||||
final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS);
|
final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS);
|
||||||
|
|
||||||
@@ -129,47 +147,16 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
|
||||||
// Send all information needed to service to import key in other thread
|
mMasterKeyIds = masterKeyIds;
|
||||||
Intent intent = new Intent(getActivity(), KeychainService.class);
|
mHasSecret = hasSecret;
|
||||||
|
|
||||||
intent.setAction(KeychainService.ACTION_DELETE);
|
mDeleteOpHelper = new CryptoOperationHelper<>
|
||||||
|
(DeleteKeyDialogFragment.this, DeleteKeyDialogFragment.this,
|
||||||
// Message is received after importing is done in KeychainService
|
R.string.progress_deleting);
|
||||||
ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
|
mDeleteOpHelper.cryptoOperation();
|
||||||
@Override
|
// do NOT dismiss here, it'll give
|
||||||
public void handleMessage(Message message) {
|
// OperationHelper a null fragmentManager
|
||||||
super.handleMessage(message);
|
// dismiss();
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
try {
|
|
||||||
Message msg = Message.obtain();
|
|
||||||
msg.copyFrom(message);
|
|
||||||
messenger.send(msg);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(Constants.TAG, "messenger error", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
data.putLongArray(KeychainService.DELETE_KEY_LIST, masterKeyIds);
|
|
||||||
data.putBoolean(KeychainService.DELETE_IS_SECRET, hasSecret);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(saveHandler);
|
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// show progress dialog
|
|
||||||
saveHandler.showProgressDialog(getString(R.string.progress_deleting),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, true);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
getActivity().startService(intent);
|
|
||||||
|
|
||||||
dismiss();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||||
@@ -183,4 +170,42 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
|||||||
return builder.show();
|
return builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeleteKeyringParcel createOperationInput() {
|
||||||
|
return new DeleteKeyringParcel(mMasterKeyIds, mHasSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationSuccess(DeleteResult result) {
|
||||||
|
handleResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationCancelled() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(DeleteResult result) {
|
||||||
|
handleResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleResult(DeleteResult result) {
|
||||||
|
try {
|
||||||
|
Bundle data = new Bundle();
|
||||||
|
data.putParcelable(OperationResult.EXTRA_RESULT, result);
|
||||||
|
Message msg = Message.obtain();
|
||||||
|
msg.arg1 = ServiceProgressHandler.MessageStatus.OKAY.ordinal();
|
||||||
|
msg.setData(data);
|
||||||
|
mMessenger.send(msg);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(Constants.TAG, "messenger error", e);
|
||||||
|
}
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,15 +18,14 @@
|
|||||||
package org.sufficientlysecure.keychain.util;
|
package org.sufficientlysecure.keychain.util;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Messenger;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
|
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
|
||||||
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
|
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
|
||||||
import org.sufficientlysecure.keychain.keyimport.Keyserver;
|
import org.sufficientlysecure.keychain.keyimport.Keyserver;
|
||||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
|
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -35,13 +34,18 @@ import java.util.Locale;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class EmailKeyHelper {
|
public class EmailKeyHelper {
|
||||||
|
// to import keys, simply use CryptoOperationHelper with this callback
|
||||||
|
public abstract class ImportContactKeysCallback
|
||||||
|
implements CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> {
|
||||||
|
|
||||||
public static void importContacts(Context context, Messenger messenger) {
|
private ArrayList<ParcelableKeyRing> mKeyList;
|
||||||
importAll(context, messenger, ContactHelper.getContactMails(context));
|
private String mKeyserver;
|
||||||
|
|
||||||
|
public ImportContactKeysCallback(Context context, String keyserver) {
|
||||||
|
this(context, ContactHelper.getContactMails(context), keyserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void importAll(Context context, Messenger messenger, List<String> mails) {
|
public ImportContactKeysCallback(Context context, List<String> mails, String keyserver) {
|
||||||
// Collect all candidates as ImportKeysListEntry (set for deduplication)
|
|
||||||
Set<ImportKeysListEntry> entries = new HashSet<>();
|
Set<ImportKeysListEntry> entries = new HashSet<>();
|
||||||
for (String mail : mails) {
|
for (String mail : mails) {
|
||||||
entries.addAll(getEmailKeys(context, mail));
|
entries.addAll(getEmailKeys(context, mail));
|
||||||
@@ -52,7 +56,13 @@ public class EmailKeyHelper {
|
|||||||
for (ImportKeysListEntry entry : entries) {
|
for (ImportKeysListEntry entry : entries) {
|
||||||
keys.add(new ParcelableKeyRing(entry.getFingerprintHex(), entry.getKeyIdHex(), null));
|
keys.add(new ParcelableKeyRing(entry.getFingerprintHex(), entry.getKeyIdHex(), null));
|
||||||
}
|
}
|
||||||
importKeys(context, messenger, keys);
|
mKeyList = keys;
|
||||||
|
mKeyserver = keyserver;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public ImportKeyringParcel createOperationInput() {
|
||||||
|
return new ImportKeyringParcel(mKeyList, mKeyserver);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<ImportKeysListEntry> getEmailKeys(Context context, String mail) {
|
public static Set<ImportKeysListEntry> getEmailKeys(Context context, String mail) {
|
||||||
@@ -78,17 +88,6 @@ public class EmailKeyHelper {
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void importKeys(Context context, Messenger messenger, ArrayList<ParcelableKeyRing> keys) {
|
|
||||||
Intent importIntent = new Intent(context, KeychainService.class);
|
|
||||||
importIntent.setAction(KeychainService.ACTION_IMPORT_KEYRING);
|
|
||||||
Bundle importData = new Bundle();
|
|
||||||
importData.putParcelableArrayList(KeychainService.IMPORT_KEY_LIST, keys);
|
|
||||||
importIntent.putExtra(KeychainService.EXTRA_DATA, importData);
|
|
||||||
importIntent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
context.startService(importIntent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<ImportKeysListEntry> getEmailKeys(String mail, Keyserver keyServer) {
|
public static List<ImportKeysListEntry> getEmailKeys(String mail, Keyserver keyServer) {
|
||||||
Set<ImportKeysListEntry> keys = new HashSet<>();
|
Set<ImportKeysListEntry> keys = new HashSet<>();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -17,26 +17,26 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.util;
|
package org.sufficientlysecure.keychain.util;
|
||||||
|
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.Messenger;
|
|
||||||
import android.support.v4.app.FragmentActivity;
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainService;
|
import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
public class ExportHelper {
|
public class ExportHelper
|
||||||
|
implements CryptoOperationHelper.Callback <ExportKeyringParcel, ExportResult> {
|
||||||
protected File mExportFile;
|
protected File mExportFile;
|
||||||
|
|
||||||
FragmentActivity mActivity;
|
FragmentActivity mActivity;
|
||||||
|
|
||||||
|
private CryptoOperationHelper<ExportKeyringParcel, ExportResult> mExportOpHelper;
|
||||||
|
private boolean mExportSecret;
|
||||||
|
private long[] mMasterKeyIds;
|
||||||
|
|
||||||
public ExportHelper(FragmentActivity activity) {
|
public ExportHelper(FragmentActivity activity) {
|
||||||
super();
|
super();
|
||||||
this.mActivity = activity;
|
this.mActivity = activity;
|
||||||
@@ -71,60 +71,43 @@ public class ExportHelper {
|
|||||||
}, mActivity.getSupportFragmentManager() ,title, message, exportFile, checkMsg);
|
}, mActivity.getSupportFragmentManager() ,title, message, exportFile, checkMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: If ExportHelper requires pending data (see CryptoOPerationHelper), activities using
|
||||||
|
// TODO: this class should be able to call mExportOpHelper.handleActivity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export keys
|
* Export keys
|
||||||
*/
|
*/
|
||||||
public void exportKeys(long[] masterKeyIds, boolean exportSecret) {
|
public void exportKeys(long[] masterKeyIds, boolean exportSecret) {
|
||||||
Log.d(Constants.TAG, "exportKeys started");
|
Log.d(Constants.TAG, "exportKeys started");
|
||||||
|
mExportSecret = exportSecret;
|
||||||
|
mMasterKeyIds = masterKeyIds; // if masterKeyIds is null it means export all
|
||||||
|
|
||||||
// Send all information needed to service to export key in other thread
|
mExportOpHelper = new CryptoOperationHelper(mActivity, this, R.string.progress_exporting);
|
||||||
final Intent intent = new Intent(mActivity, KeychainService.class);
|
mExportOpHelper.cryptoOperation();
|
||||||
|
|
||||||
intent.setAction(KeychainService.ACTION_EXPORT_KEYRING);
|
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
|
|
||||||
data.putString(KeychainService.EXPORT_FILENAME, mExportFile.getAbsolutePath());
|
|
||||||
data.putBoolean(KeychainService.EXPORT_SECRET, exportSecret);
|
|
||||||
|
|
||||||
if (masterKeyIds == null) {
|
|
||||||
data.putBoolean(KeychainService.EXPORT_ALL, true);
|
|
||||||
} else {
|
|
||||||
data.putLongArray(KeychainService.EXPORT_KEY_RING_MASTER_KEY_ID, masterKeyIds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
intent.putExtra(KeychainService.EXTRA_DATA, data);
|
|
||||||
|
|
||||||
// Message is received after exporting is done in KeychainService
|
|
||||||
ServiceProgressHandler exportHandler = new ServiceProgressHandler(mActivity) {
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message message) {
|
public ExportKeyringParcel createOperationInput() {
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
return new ExportKeyringParcel(mMasterKeyIds, mExportSecret, mExportFile.getAbsolutePath());
|
||||||
super.handleMessage(message);
|
}
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
@Override
|
||||||
// get returned data bundle
|
public void onCryptoOperationSuccess(ExportResult result) {
|
||||||
Bundle data = message.getData();
|
|
||||||
|
|
||||||
ExportResult result = data.getParcelable(ExportResult.EXTRA_RESULT);
|
|
||||||
result.createNotify(mActivity).show();
|
result.createNotify(mActivity).show();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
@Override
|
||||||
Messenger messenger = new Messenger(exportHandler);
|
public void onCryptoOperationCancelled() {
|
||||||
intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// show progress dialog
|
|
||||||
exportHandler.showProgressDialog(
|
|
||||||
mActivity.getString(R.string.progress_exporting),
|
|
||||||
ProgressDialog.STYLE_HORIZONTAL, false
|
|
||||||
);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
mActivity.startService(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCryptoOperationError(ExportResult result) {
|
||||||
|
result.createNotify(mActivity).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCryptoSetProgress(String msg, int progress, int max) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1214,6 +1214,15 @@
|
|||||||
|
|
||||||
<string name="msg_download_query_failed">"An error occurred when searching for keys."</string>
|
<string name="msg_download_query_failed">"An error occurred when searching for keys."</string>
|
||||||
|
|
||||||
|
<!-- Messages for Keybase Verification operation -->
|
||||||
|
<string name="msg_keybase_verification">"Attempting keybase verification for %s"</string>
|
||||||
|
<string name="msg_keybase_error_no_prover">"No proof checker found for %s"</string>
|
||||||
|
<string name="msg_keybase_error_fetching_evidence">"Problem with fetching proof"</string>
|
||||||
|
<string name="msg_keybase_error_key_mismatch">"Key fingerprint doesn’t match that in proof post"</string>
|
||||||
|
<string name="msg_keybase_error_dns_fail">"DNS TXT Record retrieval failed"</string>
|
||||||
|
<string name="msg_keybase_error_specific">"%s"</string>
|
||||||
|
<string name="msg_keybase_error_msg_payload_mismatch">"Decrypted proof post does not match expected value"</string>
|
||||||
|
|
||||||
<!-- Messages for Export Log operation -->
|
<!-- Messages for Export Log operation -->
|
||||||
<string name="msg_export_log_start">"Exporting log"</string>
|
<string name="msg_export_log_start">"Exporting log"</string>
|
||||||
<string name="msg_export_log_error_fopen">"Error opening file"</string>
|
<string name="msg_export_log_error_fopen">"Error opening file"</string>
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import org.robolectric.annotation.Config;
|
|||||||
import org.robolectric.shadows.ShadowLog;
|
import org.robolectric.shadows.ShadowLog;
|
||||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||||
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.sufficientlysecure.keychain.BuildConfig;
|
|
||||||
import org.sufficientlysecure.keychain.WorkaroundBuildConfig;
|
import org.sufficientlysecure.keychain.WorkaroundBuildConfig;
|
||||||
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
||||||
@@ -127,7 +126,7 @@ public class ExportTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExportAll() throws Exception {
|
public void testExportAll() throws Exception {
|
||||||
ImportExportOperation op = new ImportExportOperation(RuntimeEnvironment.application,
|
ExportOperation op = new ExportOperation(RuntimeEnvironment.application,
|
||||||
new ProviderHelper(RuntimeEnvironment.application), null);
|
new ProviderHelper(RuntimeEnvironment.application), null);
|
||||||
|
|
||||||
// make sure there is a local cert (so the later checks that there are none are meaningful)
|
// make sure there is a local cert (so the later checks that there are none are meaningful)
|
||||||
|
|||||||
Reference in New Issue
Block a user