rewrite export with new operation style
This commit is contained in:
@@ -19,34 +19,37 @@
|
|||||||
package org.sufficientlysecure.keychain.operations;
|
package org.sufficientlysecure.keychain.operations;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.database.Cursor;
|
||||||
import android.os.Environment;
|
import android.net.Uri;
|
||||||
|
|
||||||
import org.spongycastle.bcpg.ArmoredOutputStream;
|
import org.spongycastle.bcpg.ArmoredOutputStream;
|
||||||
import org.spongycastle.openpgp.PGPException;
|
|
||||||
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.Keyserver.AddKeyException;
|
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.ExportResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||||
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;
|
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.KeychainIntentService;
|
|
||||||
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.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
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.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -92,6 +95,7 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
updateProgress(R.string.progress_importing, 0, 100);
|
updateProgress(R.string.progress_importing, 0, 100);
|
||||||
|
|
||||||
OperationLog log = new OperationLog();
|
OperationLog log = new OperationLog();
|
||||||
|
log.add(LogType.MSG_IMPORT, 0, num);
|
||||||
|
|
||||||
// If there aren't even any keys, do nothing here.
|
// If there aren't even any keys, do nothing here.
|
||||||
if (entries == null || !entries.hasNext()) {
|
if (entries == null || !entries.hasNext()) {
|
||||||
@@ -103,6 +107,7 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
int newKeys = 0, oldKeys = 0, badKeys = 0, secret = 0;
|
int newKeys = 0, oldKeys = 0, badKeys = 0, secret = 0;
|
||||||
ArrayList<Long> importedMasterKeyIds = new ArrayList<Long>();
|
ArrayList<Long> importedMasterKeyIds = new ArrayList<Long>();
|
||||||
|
|
||||||
|
boolean cancelled = false;
|
||||||
int position = 0;
|
int position = 0;
|
||||||
double progSteps = 100.0 / num;
|
double progSteps = 100.0 / num;
|
||||||
|
|
||||||
@@ -111,7 +116,8 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
ParcelableKeyRing entry = entries.next();
|
ParcelableKeyRing entry = entries.next();
|
||||||
|
|
||||||
// Has this action been cancelled? If so, don't proceed any further
|
// Has this action been cancelled? If so, don't proceed any further
|
||||||
if (mCancelled != null && mCancelled.get()) {
|
if (checkCancelled()) {
|
||||||
|
cancelled = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +172,18 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
position++;
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convert to long array
|
||||||
|
long[] importedMasterKeyIdsArray = new long[importedMasterKeyIds.size()];
|
||||||
|
for (int i = 0; i < importedMasterKeyIds.size(); ++i) {
|
||||||
|
importedMasterKeyIdsArray[i] = importedMasterKeyIds.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
int resultType = 0;
|
int resultType = 0;
|
||||||
|
if (cancelled) {
|
||||||
|
log.add(LogType.MSG_OPERATION_CANCELLED, 1);
|
||||||
|
resultType |= ImportKeyResult.RESULT_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
// special return case: no new keys at all
|
// special return case: no new keys at all
|
||||||
if (badKeys == 0 && newKeys == 0 && oldKeys == 0) {
|
if (badKeys == 0 && newKeys == 0 && oldKeys == 0) {
|
||||||
resultType = ImportKeyResult.RESULT_FAIL_NOTHING;
|
resultType = ImportKeyResult.RESULT_FAIL_NOTHING;
|
||||||
@@ -187,93 +204,178 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
resultType |= ImportKeyResult.RESULT_WARNINGS;
|
resultType |= ImportKeyResult.RESULT_WARNINGS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mCancelled != null && mCancelled.get()) {
|
|
||||||
log.add(LogType.MSG_OPERATION_CANCELLED, 0);
|
|
||||||
resultType |= ImportKeyResult.RESULT_CANCELLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert to long array
|
// Final log entry, it's easier to do this individually
|
||||||
long[] importedMasterKeyIdsArray = new long[importedMasterKeyIds.size()];
|
if ( (newKeys > 0 || oldKeys > 0) && badKeys > 0) {
|
||||||
for (int i = 0; i < importedMasterKeyIds.size(); ++i) {
|
log.add(LogType.MSG_IMPORT_PARTIAL, 1);
|
||||||
importedMasterKeyIdsArray[i] = importedMasterKeyIds.get(i);
|
} else if (newKeys > 0 || oldKeys > 0) {
|
||||||
|
log.add(LogType.MSG_IMPORT_SUCCESS, 1);
|
||||||
|
} else {
|
||||||
|
log.add(LogType.MSG_IMPORT_ERROR, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys, secret,
|
return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys, secret,
|
||||||
importedMasterKeyIdsArray);
|
importedMasterKeyIdsArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bundle exportKeyRings(ArrayList<Long> publicKeyRingMasterIds,
|
public ExportResult exportToFile(long[] masterKeyIds, boolean exportSecret, String outputFile) {
|
||||||
ArrayList<Long> secretKeyRingMasterIds,
|
|
||||||
OutputStream outStream) throws PgpGeneralException,
|
|
||||||
PGPException, IOException {
|
|
||||||
Bundle returnData = new Bundle();
|
|
||||||
|
|
||||||
int masterKeyIdsSize = publicKeyRingMasterIds.size() + secretKeyRingMasterIds.size();
|
OperationLog log = new OperationLog();
|
||||||
int progress = 0;
|
if (masterKeyIds != null) {
|
||||||
|
log.add(LogType.MSG_EXPORT, 0, masterKeyIds.length);
|
||||||
|
} else {
|
||||||
|
log.add(LogType.MSG_EXPORT_ALL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
updateProgress(
|
// do we have a file name?
|
||||||
mContext.getResources().getQuantityString(R.plurals.progress_exporting_key,
|
if (outputFile == null) {
|
||||||
masterKeyIdsSize), 0, 100);
|
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);
|
||||||
|
ExportResult result = exportKeyRings(log, masterKeyIds, exportSecret, outStream);
|
||||||
|
if (result.cancelled()) {
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
|
new File(outputFile).delete();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (FileNotFoundException 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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)) {
|
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||||
throw new PgpGeneralException(
|
log.add(LogType.MSG_EXPORT_ERROR_STORAGE, 1);
|
||||||
mContext.getString(R.string.error_external_storage_not_ready));
|
return new ExportResult(ExportResult.RESULT_ERROR, log);
|
||||||
}
|
}
|
||||||
// For each public masterKey id
|
*/
|
||||||
for (long pubKeyMasterId : publicKeyRingMasterIds) {
|
|
||||||
progress++;
|
int okSecret = 0, okPublic = 0, progress = 0;
|
||||||
// Create an output stream
|
|
||||||
ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream);
|
try {
|
||||||
String version = PgpHelper.getVersionForHeader(mContext);
|
|
||||||
if (version != null) {
|
String selection = null, ids[] = null;
|
||||||
arOutStream.setHeader("Version", version);
|
|
||||||
|
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 + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProgress(progress * 100 / masterKeyIdsSize, 100);
|
Cursor 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
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
if (cursor == null || !cursor.moveToFirst()) {
|
||||||
CanonicalizedPublicKeyRing ring = mProviderHelper.getCanonicalizedPublicKeyRing(
|
log.add(LogType.MSG_EXPORT_ERROR_DB, 1);
|
||||||
KeychainContract.KeyRings.buildUnifiedKeyRingUri(pubKeyMasterId)
|
return new ExportResult(ExportResult.RESULT_ERROR, log, okPublic, okSecret);
|
||||||
);
|
|
||||||
|
|
||||||
ring.encode(arOutStream);
|
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
|
||||||
Log.e(Constants.TAG, "key not found!", e);
|
|
||||||
// TODO: inform user?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arOutStream.close();
|
int numKeys = cursor.getCount();
|
||||||
|
|
||||||
|
updateProgress(
|
||||||
|
mContext.getResources().getQuantityString(R.plurals.progress_exporting_key,
|
||||||
|
numKeys), 0, numKeys);
|
||||||
|
|
||||||
|
// For each public masterKey id
|
||||||
|
while (!cursor.isAfterLast()) {
|
||||||
|
|
||||||
|
// Create an output stream
|
||||||
|
ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream);
|
||||||
|
String version = PgpHelper.getVersionForHeader(mContext);
|
||||||
|
if (version != null) {
|
||||||
|
arOutStream.setHeader("Version", version);
|
||||||
|
}
|
||||||
|
|
||||||
|
long keyId = cursor.getLong(0);
|
||||||
|
|
||||||
|
log.add(LogType.MSG_EXPORT_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(keyId));
|
||||||
|
|
||||||
|
{ // export public key part
|
||||||
|
byte[] data = cursor.getBlob(1);
|
||||||
|
arOutStream.write(data);
|
||||||
|
arOutStream.close();
|
||||||
|
|
||||||
|
okPublic += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// export secret key part
|
||||||
|
if (exportSecret && cursor.getInt(3) > 0) {
|
||||||
|
log.add(LogType.MSG_EXPORT_SECRET, 2, KeyFormattingUtils.beautifyKeyId(keyId));
|
||||||
|
byte[] data = cursor.getBlob(2);
|
||||||
|
arOutStream.write(data);
|
||||||
|
|
||||||
|
okSecret += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each secret masterKey id
|
|
||||||
for (long secretKeyMasterId : secretKeyRingMasterIds) {
|
|
||||||
progress++;
|
|
||||||
// Create an output stream
|
|
||||||
ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream);
|
|
||||||
String version = PgpHelper.getVersionForHeader(mContext);
|
|
||||||
if (version != null) {
|
|
||||||
arOutStream.setHeader("Version", version);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateProgress(progress * 100 / masterKeyIdsSize, 100);
|
log.add(LogType.MSG_EXPORT_SUCCESS, 1);
|
||||||
|
return new ExportResult(ExportResult.RESULT_OK, log, okPublic, okSecret);
|
||||||
|
|
||||||
try {
|
|
||||||
CanonicalizedSecretKeyRing secretKeyRing =
|
|
||||||
mProviderHelper.getCanonicalizedSecretKeyRing(secretKeyMasterId);
|
|
||||||
secretKeyRing.encode(arOutStream);
|
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
|
||||||
Log.e(Constants.TAG, "key not found!", e);
|
|
||||||
// TODO: inform user?
|
|
||||||
}
|
|
||||||
|
|
||||||
arOutStream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
returnData.putInt(KeychainIntentService.RESULT_EXPORT, masterKeyIdsSize);
|
|
||||||
|
|
||||||
updateProgress(R.string.progress_done, 100, 100);
|
|
||||||
|
|
||||||
return returnData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -580,6 +580,24 @@ public abstract class OperationResult implements Parcelable {
|
|||||||
MSG_CRT_WARN_CERT_FAILED (LogLevel.WARN, R.string.msg_crt_warn_cert_failed),
|
MSG_CRT_WARN_CERT_FAILED (LogLevel.WARN, R.string.msg_crt_warn_cert_failed),
|
||||||
MSG_CRT_WARN_SAVE_FAILED (LogLevel.WARN, R.string.msg_crt_warn_save_failed),
|
MSG_CRT_WARN_SAVE_FAILED (LogLevel.WARN, R.string.msg_crt_warn_save_failed),
|
||||||
|
|
||||||
|
MSG_IMPORT (LogLevel.START, R.plurals.msg_import),
|
||||||
|
MSG_IMPORT_ERROR (LogLevel.ERROR, R.string.msg_import_error),
|
||||||
|
MSG_IMPORT_PARTIAL (LogLevel.ERROR, R.string.msg_import_partial),
|
||||||
|
MSG_IMPORT_SUCCESS (LogLevel.OK, R.string.msg_import_success),
|
||||||
|
|
||||||
|
MSG_EXPORT (LogLevel.START, R.plurals.msg_export),
|
||||||
|
MSG_EXPORT_PUBLIC (LogLevel.DEBUG, R.string.msg_export_public),
|
||||||
|
MSG_EXPORT_SECRET (LogLevel.DEBUG, R.string.msg_export_secret),
|
||||||
|
MSG_EXPORT_ALL (LogLevel.START, R.string.msg_export_all),
|
||||||
|
MSG_EXPORT_ERROR_NO_FILE (LogLevel.ERROR, R.string.msg_export_error_no_file),
|
||||||
|
MSG_EXPORT_ERROR_FOPEN (LogLevel.ERROR, R.string.msg_export_error_fopen),
|
||||||
|
MSG_EXPORT_ERROR_NO_URI (LogLevel.ERROR, R.string.msg_export_error_no_uri),
|
||||||
|
MSG_EXPORT_ERROR_URI_OPEN (LogLevel.ERROR, R.string.msg_export_error_uri_open),
|
||||||
|
MSG_EXPORT_ERROR_STORAGE (LogLevel.ERROR, R.string.msg_export_error_storage),
|
||||||
|
MSG_EXPORT_ERROR_DB (LogLevel.ERROR, R.string.msg_export_error_db),
|
||||||
|
MSG_EXPORT_ERROR_IO (LogLevel.ERROR, R.string.msg_export_error_io),
|
||||||
|
MSG_EXPORT_SUCCESS (LogLevel.OK, R.string.msg_export_success),
|
||||||
|
|
||||||
MSG_CRT_UPLOAD_SUCCESS (LogLevel.OK, R.string.msg_crt_upload_success),
|
MSG_CRT_UPLOAD_SUCCESS (LogLevel.OK, R.string.msg_crt_upload_success),
|
||||||
|
|
||||||
MSG_ACC_SAVED (LogLevel.INFO, R.string.api_settings_save_msg),
|
MSG_ACC_SAVED (LogLevel.INFO, R.string.api_settings_save_msg),
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.R;
|
|||||||
import org.sufficientlysecure.keychain.operations.CertifyOperation;
|
import org.sufficientlysecure.keychain.operations.CertifyOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.DeleteOperation;
|
import org.sufficientlysecure.keychain.operations.DeleteOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
|
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
|
||||||
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
||||||
@@ -356,12 +357,15 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
|
|
||||||
} else if (ACTION_DELETE.equals(action)) {
|
} else if (ACTION_DELETE.equals(action)) {
|
||||||
|
|
||||||
|
// Input
|
||||||
long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST);
|
long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST);
|
||||||
boolean isSecret = data.getBoolean(DELETE_IS_SECRET);
|
boolean isSecret = data.getBoolean(DELETE_IS_SECRET);
|
||||||
|
|
||||||
|
// Operation
|
||||||
DeleteOperation op = new DeleteOperation(this, new ProviderHelper(this), this);
|
DeleteOperation op = new DeleteOperation(this, new ProviderHelper(this), this);
|
||||||
DeleteResult result = op.execute(masterKeyIds, isSecret);
|
DeleteResult result = op.execute(masterKeyIds, isSecret);
|
||||||
|
|
||||||
|
// Result
|
||||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||||
|
|
||||||
} else if (ACTION_DELETE_FILE_SECURELY.equals(action)) {
|
} else if (ACTION_DELETE_FILE_SECURELY.equals(action)) {
|
||||||
@@ -523,72 +527,27 @@ public class KeychainIntentService extends IntentService implements Progressable
|
|||||||
|
|
||||||
} else if (ACTION_EXPORT_KEYRING.equals(action)) {
|
} else if (ACTION_EXPORT_KEYRING.equals(action)) {
|
||||||
|
|
||||||
try {
|
// Input
|
||||||
|
boolean exportSecret = data.getBoolean(EXPORT_SECRET, false);
|
||||||
|
String outputFile = data.getString(EXPORT_FILENAME);
|
||||||
|
Uri outputUri = data.getParcelable(EXPORT_URI);
|
||||||
|
|
||||||
boolean exportSecret = data.getBoolean(EXPORT_SECRET, false);
|
boolean exportAll = data.getBoolean(EXPORT_ALL);
|
||||||
long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
|
long[] masterKeyIds = exportAll ? null : data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
|
||||||
String outputFile = data.getString(EXPORT_FILENAME);
|
|
||||||
Uri outputUri = data.getParcelable(EXPORT_URI);
|
|
||||||
|
|
||||||
// If not exporting all keys get the masterKeyIds of the keys to export from the intent
|
|
||||||
boolean exportAll = data.getBoolean(EXPORT_ALL);
|
|
||||||
|
|
||||||
if (outputFile != null) {
|
// Operation
|
||||||
// check if storage is ready
|
ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this);
|
||||||
if (!FileHelper.isStorageMounted(outputFile)) {
|
ExportResult result;
|
||||||
throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
|
if (outputFile != null) {
|
||||||
}
|
result = importExportOperation.exportToFile(masterKeyIds, exportSecret, outputFile);
|
||||||
}
|
} else {
|
||||||
|
result = importExportOperation.exportToUri(masterKeyIds, exportSecret, outputUri);
|
||||||
ArrayList<Long> publicMasterKeyIds = new ArrayList<Long>();
|
|
||||||
ArrayList<Long> secretMasterKeyIds = new ArrayList<Long>();
|
|
||||||
|
|
||||||
String selection = null;
|
|
||||||
if (!exportAll) {
|
|
||||||
selection = KeychainDatabase.Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + " IN( ";
|
|
||||||
for (long l : masterKeyIds) {
|
|
||||||
selection += Long.toString(l) + ",";
|
|
||||||
}
|
|
||||||
selection = selection.substring(0, selection.length() - 1) + " )";
|
|
||||||
}
|
|
||||||
|
|
||||||
Cursor cursor = getContentResolver().query(KeyRings.buildUnifiedKeyRingsUri(),
|
|
||||||
new String[]{KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET},
|
|
||||||
selection, null, null);
|
|
||||||
try {
|
|
||||||
if (cursor != null && cursor.moveToFirst()) do {
|
|
||||||
// export public either way
|
|
||||||
publicMasterKeyIds.add(cursor.getLong(0));
|
|
||||||
// add secret if available (and requested)
|
|
||||||
if (exportSecret && cursor.getInt(1) != 0)
|
|
||||||
secretMasterKeyIds.add(cursor.getLong(0));
|
|
||||||
} while (cursor.moveToNext());
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputStream outStream;
|
|
||||||
if (outputFile != null) {
|
|
||||||
outStream = new FileOutputStream(outputFile);
|
|
||||||
} else {
|
|
||||||
outStream = getContentResolver().openOutputStream(outputUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this);
|
|
||||||
Bundle resultData = importExportOperation
|
|
||||||
.exportKeyRings(publicMasterKeyIds, secretMasterKeyIds, outStream);
|
|
||||||
|
|
||||||
if (mActionCanceled.get() && outputFile != null) {
|
|
||||||
new File(outputFile).delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
|
||||||
} catch (Exception e) {
|
|
||||||
sendErrorToHandler(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Result
|
||||||
|
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||||
|
|
||||||
} else if (ACTION_IMPORT_KEYRING.equals(action)) {
|
} else if (ACTION_IMPORT_KEYRING.equals(action)) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ 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.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
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;
|
||||||
@@ -127,19 +128,10 @@ public class ExportHelper {
|
|||||||
|
|
||||||
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
|
||||||
// get returned data bundle
|
// get returned data bundle
|
||||||
Bundle returnData = message.getData();
|
Bundle data = message.getData();
|
||||||
|
|
||||||
int exported = returnData.getInt(KeychainIntentService.RESULT_EXPORT);
|
|
||||||
String toastMessage;
|
|
||||||
if (exported == 1) {
|
|
||||||
toastMessage = mActivity.getString(R.string.key_exported);
|
|
||||||
} else if (exported > 0) {
|
|
||||||
toastMessage = mActivity.getString(R.string.keys_exported, exported);
|
|
||||||
} else {
|
|
||||||
toastMessage = mActivity.getString(R.string.no_keys_exported);
|
|
||||||
}
|
|
||||||
Toast.makeText(mActivity, toastMessage, Toast.LENGTH_SHORT).show();
|
|
||||||
|
|
||||||
|
ExportResult result = data.getParcelable(ExportResult.EXTRA_RESULT);
|
||||||
|
result.createNotify(mActivity).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -940,6 +940,30 @@
|
|||||||
|
|
||||||
<string name="msg_crt_upload_success">"Successfully uploaded key to server"</string>
|
<string name="msg_crt_upload_success">"Successfully uploaded key to server"</string>
|
||||||
|
|
||||||
|
<plurals name="msg_import">
|
||||||
|
<item quantity="one">"Importing key"</item>
|
||||||
|
<item quantity="other">"Importing %d keys"</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="msg_import_error">"Import operation failed!"</string>
|
||||||
|
<string name="msg_import_partial">"Import operation successful, with errors!"</string>
|
||||||
|
<string name="msg_import_success">"Import operation successful"</string>
|
||||||
|
|
||||||
|
<plurals name="msg_export">
|
||||||
|
<item quantity="one">"Exporting one keys"</item>
|
||||||
|
<item quantity="other">"Exporting %d keys"</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="msg_export_all">"Exporting all keys"</string>
|
||||||
|
<string name="msg_export_public">"Exporting public key %s"</string>
|
||||||
|
<string name="msg_export_secret">"Exporting secret key %s"</string>
|
||||||
|
<string name="msg_export_error_no_file">"No filename specified!"</string>
|
||||||
|
<string name="msg_export_error_fopen">"Error opening File!"</string>
|
||||||
|
<string name="msg_export_error_no_uri">"No URI specified!"</string>
|
||||||
|
<string name="msg_export_error_uri_open">"Error opening URI stream!"</string>
|
||||||
|
<string name="msg_export_error_storage">"Storage is not ready for writing!"</string>
|
||||||
|
<string name="msg_export_error_db">"Database error!"</string>
|
||||||
|
<string name="msg_export_error_io">"Input/output error!"</string>
|
||||||
|
<string name="msg_export_success">"Export operation successful"</string>
|
||||||
|
|
||||||
<string name="msg_del_error_empty">"Nothing to delete!"</string>
|
<string name="msg_del_error_empty">"Nothing to delete!"</string>
|
||||||
<string name="msg_del_error_multi_secret">"Secret keys can only be deleted individually!"</string>
|
<string name="msg_del_error_multi_secret">"Secret keys can only be deleted individually!"</string>
|
||||||
<plurals name="msg_del">
|
<plurals name="msg_del">
|
||||||
|
|||||||
Reference in New Issue
Block a user