From e387dd7c54ddfdbe8379b57e00fed567510fd863 Mon Sep 17 00:00:00 2001 From: uberspot Date: Sat, 15 Mar 2014 01:51:01 +0200 Subject: Fix export for new unified key list #409 --- .../java/org/sufficientlysecure/keychain/Id.java | 1 + .../keychain/helper/ExportHelper.java | 34 ++++++----- .../keychain/pgp/PgpImportExport.java | 69 ++++++++++++---------- .../keychain/service/KeychainIntentService.java | 50 ++++++++-------- .../keychain/ui/EditKeyActivity.java | 6 +- .../keychain/ui/KeyListActivity.java | 5 +- .../keychain/ui/KeyListFragment.java | 18 ++++-- .../keychain/ui/ViewKeyActivity.java | 7 ++- 8 files changed, 111 insertions(+), 79 deletions(-) (limited to 'OpenPGP-Keychain/src/main/java') diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java index 1d79edd43..784ec340e 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java @@ -119,6 +119,7 @@ public final class Id { public static final int secret_key = 0x21070002; public static final int user_id = 0x21070003; public static final int key = 0x21070004; + public static final int public_secret_key = 0x21070005; } public static final class choice { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java index 557d75dbf..03cf936ee 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java @@ -30,12 +30,18 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; import org.sufficientlysecure.keychain.util.Log; +import java.lang.reflect.Array; +import java.security.Provider; +import java.util.ArrayList; + public class ExportHelper { protected FileDialogFragment mFileDialog; protected String mExportFilename; @@ -62,8 +68,8 @@ public class ExportHelper { /** * Show dialog where to export keys */ - public void showExportKeysDialog(final long[] rowIds, final int keyType, - final String exportFilename) { + public void showExportKeysDialog(final long[] masterKeyIds, final int keyType, + final String exportFilename, final String checkboxString) { mExportFilename = exportFilename; // Message is received after file is selected @@ -72,9 +78,14 @@ public class ExportHelper { public void handleMessage(Message message) { if (message.what == FileDialogFragment.MESSAGE_OKAY) { Bundle data = message.getData(); + int type = keyType; mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); - exportKeys(rowIds, keyType); + if( data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED) ) { + type = Id.type.public_secret_key; + } + + exportKeys(masterKeyIds, type); } } }; @@ -85,7 +96,7 @@ public class ExportHelper { DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { public void run() { String title = null; - if (rowIds == null) { + if (masterKeyIds == null) { // export all keys title = mActivity.getString(R.string.title_export_keys); } else { @@ -93,15 +104,10 @@ public class ExportHelper { title = mActivity.getString(R.string.title_export_key); } - String message = null; - if (keyType == Id.type.public_key) { - message = mActivity.getString(R.string.specify_file_to_export_to); - } else { - message = mActivity.getString(R.string.specify_file_to_export_secret_keys_to); - } + String message = mActivity.getString(R.string.specify_file_to_export_to); mFileDialog = FileDialogFragment.newInstance(messenger, title, message, - exportFilename, null); + exportFilename, checkboxString); mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog"); } @@ -111,7 +117,7 @@ public class ExportHelper { /** * Export keys */ - public void exportKeys(long[] rowIds, int keyType) { + public void exportKeys(long[] masterKeyIds, int keyType) { Log.d(Constants.TAG, "exportKeys started"); // Send all information needed to service to export key in other thread @@ -125,10 +131,10 @@ public class ExportHelper { data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename); data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType); - if (rowIds == null) { + if (masterKeyIds == null) { data.putBoolean(KeychainIntentService.EXPORT_ALL, true); } else { - data.putLongArray(KeychainIntentService.EXPORT_KEY_RING_ROW_ID, rowIds); + data.putLongArray(KeychainIntentService.EXPORT_KEY_RING_MASTER_KEY_ID, masterKeyIds); } intent.putExtra(KeychainIntentService.EXTRA_DATA, data); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index dbfa521e5..0e0fdec83 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.security.Provider; import java.util.ArrayList; import java.util.List; @@ -158,60 +159,68 @@ public class PgpImportExport { return returnData; } - public Bundle exportKeyRings(ArrayList keyRingRowIds, int keyType, + public Bundle exportKeyRings(ArrayList publicKeyRingMasterIds, ArrayList secretKeyRingMasterIds, OutputStream outStream) throws PgpGeneralException, PGPException, IOException { Bundle returnData = new Bundle(); - int rowIdsSize = keyRingRowIds.size(); + int masterKeyIdsSize = publicKeyRingMasterIds.size() + secretKeyRingMasterIds.size(); + int progress = 0; updateProgress( mContext.getResources().getQuantityString(R.plurals.progress_exporting_key, - rowIdsSize), 0, 100); + masterKeyIdsSize), 0, 100); if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { throw new PgpGeneralException( mContext.getString(R.string.error_external_storage_not_ready)); } - // For each row id - for (int i = 0; i < rowIdsSize; ++i) { + // For each public masterKey id + for (long pubKeyMasterId : publicKeyRingMasterIds) { + progress++; // Create an output stream ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream); arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext)); - // If the keyType is secret get the PGPSecretKeyRing - // based on the row id and encode it to the output - if (keyType == Id.type.secret_key) { - updateProgress(i * 100 / rowIdsSize / 2, 100); - PGPSecretKeyRing secretKeyRing = - ProviderHelper.getPGPSecretKeyRingByRowId(mContext, keyRingRowIds.get(i)); + updateProgress(progress * 100 / masterKeyIdsSize, 100); + PGPPublicKeyRing publicKeyRing = + ProviderHelper.getPGPPublicKeyRingByMasterKeyId(mContext, pubKeyMasterId); - if (secretKeyRing != null) { - secretKeyRing.encode(arOutStream); - } - if (mKeychainServiceListener.hasServiceStopped()) { - arOutStream.close(); - return null; - } - } else { - updateProgress(i * 100 / rowIdsSize, 100); - PGPPublicKeyRing publicKeyRing = - ProviderHelper.getPGPPublicKeyRingByRowId(mContext, keyRingRowIds.get(i)); + if (publicKeyRing != null) { + publicKeyRing.encode(arOutStream); + } - if (publicKeyRing != null) { - publicKeyRing.encode(arOutStream); - } + if (mKeychainServiceListener.hasServiceStopped()) { + arOutStream.close(); + return null; + } - if (mKeychainServiceListener.hasServiceStopped()) { - arOutStream.close(); - return null; - } + arOutStream.close(); + } + + // For each secret masterKey id + for (long secretKeyMasterId : secretKeyRingMasterIds) { + progress++; + // Create an output stream + ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream); + arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext)); + + updateProgress(progress * 100 / masterKeyIdsSize, 100); + PGPSecretKeyRing secretKeyRing = + ProviderHelper.getPGPSecretKeyRingByMasterKeyId(mContext, secretKeyMasterId); + + if (secretKeyRing != null) { + secretKeyRing.encode(arOutStream); + } + if (mKeychainServiceListener.hasServiceStopped()) { + arOutStream.close(); + return null; } arOutStream.close(); } - returnData.putInt(KeychainIntentService.RESULT_EXPORT, rowIdsSize); + returnData.putInt(KeychainIntentService.RESULT_EXPORT, masterKeyIdsSize); updateProgress(R.string.progress_done, 100, 100); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 4e5812202..a44b121ec 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -131,7 +131,6 @@ public class KeychainIntentService extends IntentService public static final String EXPORT_KEY_TYPE = "export_key_type"; public static final String EXPORT_ALL = "export_all"; public static final String EXPORT_KEY_RING_MASTER_KEY_ID = "export_key_ring_id"; - public static final String EXPORT_KEY_RING_ROW_ID = "export_key_rind_row_id"; // upload key public static final String UPLOAD_KEY_SERVER = "upload_key_server"; @@ -660,16 +659,11 @@ public class KeychainIntentService extends IntentService if (data.containsKey(EXPORT_KEY_TYPE)) { keyType = data.getInt(EXPORT_KEY_TYPE); } - + long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID); String outputFile = data.getString(EXPORT_FILENAME); - long[] rowIds = new long[0]; - - // If not exporting all keys get the rowIds of the keys to export from the intent + // If not exporting all keys get the masterKeyIds of the keys to export from the intent boolean exportAll = data.getBoolean(EXPORT_ALL); - if (!exportAll) { - rowIds = data.getLongArray(EXPORT_KEY_RING_ROW_ID); - } /* Operation */ @@ -678,30 +672,38 @@ public class KeychainIntentService extends IntentService throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready)); } - // OutputStream - FileOutputStream outStream = new FileOutputStream(outputFile); + ArrayList publicMasterKeyIds = new ArrayList(); + ArrayList secretMasterKeyIds = new ArrayList(); + ArrayList allPublicMasterKeyIds = ProviderHelper.getPublicKeyRingsMasterKeyIds(this); + ArrayList allSecretMasterKeyIds = ProviderHelper.getSecretKeyRingsMasterKeyIds(this); - ArrayList keyRingRowIds = new ArrayList(); if (exportAll) { - - // get all key ring row ids based on export type - if (keyType == Id.type.public_key) { - keyRingRowIds = ProviderHelper.getPublicKeyRingsRowIds(this); - } else { - keyRingRowIds = ProviderHelper.getSecretKeyRingsRowIds(this); + // get all public key ring MasterKey ids + if (keyType == Id.type.public_key || keyType == Id.type.public_secret_key) { + publicMasterKeyIds = allPublicMasterKeyIds; + } + // get all secret key ring MasterKey ids + if (keyType == Id.type.secret_key || keyType == Id.type.public_secret_key) { + secretMasterKeyIds = allSecretMasterKeyIds; } } else { - for (long rowId : rowIds) { - keyRingRowIds.add(rowId); + + for (long masterKeyId : masterKeyIds) { + if ((keyType == Id.type.public_key || keyType == Id.type.public_secret_key) + && allPublicMasterKeyIds.contains(masterKeyId)) { + publicMasterKeyIds.add(masterKeyId); + } + if ((keyType == Id.type.secret_key || keyType == Id.type.public_secret_key) + && allSecretMasterKeyIds.contains(masterKeyId)) { + secretMasterKeyIds.add(masterKeyId); + } } } - Bundle resultData; - PgpImportExport pgpImportExport = new PgpImportExport(this, this, this); - - resultData = pgpImportExport - .exportKeyRings(keyRingRowIds, keyType, outStream); + Bundle resultData = pgpImportExport + .exportKeyRings(publicMasterKeyIds, secretMasterKeyIds, + new FileOutputStream(outputFile)); if (mIsCanceled) { boolean isDeleted = new File(outputFile).delete(); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index edf980773..7edb61b09 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -322,8 +322,10 @@ public class EditKeyActivity extends ActionBarActivity { cancelClicked(); return true; case R.id.menu_key_edit_export_file: - long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())}; - mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC); + long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri); + long[] ids = new long[]{masterKeyId}; + mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC, + null); return true; case R.id.menu_key_edit_delete: { // Message is received after key is deleted diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java index 078b998e1..5ff4dbdeb 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -58,8 +58,7 @@ public class KeyListActivity extends DrawerActivity { return true; case R.id.menu_key_list_export: - // TODO fix this for unified keylist - mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB); + mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB, null); return true; case R.id.menu_key_list_create: @@ -71,7 +70,7 @@ public class KeyListActivity extends DrawerActivity { return true; case R.id.menu_key_list_secret_export: - mExportHelper.showExportKeysDialog(null, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC); + mExportHelper.showExportKeysDialog(null, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC, null); return true; default: diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 5ac59965d..cac8b7046 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -49,6 +49,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.provider.KeychainDatabase; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.util.Log; @@ -183,13 +184,22 @@ public class KeyListFragment extends Fragment break; } case R.id.menu_key_list_multi_export: { - // todo: public/secret needs to be handled differently here ids = mStickyList.getWrappedList().getCheckedItemIds(); + long[] masterKeyIds = new long[2*ids.length]; + ArrayList allPubRowIds = + ProviderHelper.getPublicKeyRingsRowIds(getActivity()); + for (int i = 0; i < ids.length; i++) { + if (allPubRowIds.contains(ids[i])) { + masterKeyIds[i] = ProviderHelper.getPublicMasterKeyId(getActivity(), ids[i]); + } else { + masterKeyIds[i] = ProviderHelper.getSecretMasterKeyId(getActivity(), ids[i]); + } + } ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity()); mExportHelper - .showExportKeysDialog(ids, - Id.type.public_key, - Constants.Path.APP_DIR_FILE_PUB); + .showExportKeysDialog(masterKeyIds, Id.type.public_key, + Constants.Path.APP_DIR_FILE_PUB, + getString(R.string.also_export_secret_keys)); break; } case R.id.menu_key_list_multi_select_all: { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 93bb83003..c4097403c 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -124,8 +124,11 @@ public class ViewKeyActivity extends ActionBarActivity { uploadToKeyserver(mDataUri); return true; case R.id.menu_key_view_export_file: - long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())}; - mExportHelper.showExportKeysDialog(ids, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB); + long masterKeyId = + ProviderHelper.getPublicMasterKeyId(this, Long.valueOf(mDataUri.getLastPathSegment())); + long[] ids = new long[]{masterKeyId}; + mExportHelper.showExportKeysDialog(ids, Id.type.public_key, + Constants.Path.APP_DIR_FILE_PUB, null); return true; case R.id.menu_key_view_share_default_fingerprint: shareKey(mDataUri, true); -- cgit v1.2.3