From d7c2488a0f08c8314706f76c22b53166309bcdf0 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 4 Apr 2014 18:49:45 +0200 Subject: [PATCH] db-overhaul: fix key export (and some export-related ui changes) --- .../keychain/helper/ExportHelper.java | 19 +++---- .../service/KeychainIntentService.java | 56 +++++++++---------- .../keychain/ui/EditKeyActivity.java | 5 +- .../keychain/ui/KeyListActivity.java | 15 ++--- .../keychain/ui/KeyListFragment.java | 23 ++++++-- .../keychain/ui/ViewKeyActivity.java | 11 ++-- .../keychain/ui/ViewKeyMainFragment.java | 16 +++++- .../src/main/res/menu/key_list.xml | 11 ---- 8 files changed, 76 insertions(+), 80 deletions(-) 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 3040b4e9c..810f22d8e 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 @@ -61,8 +61,8 @@ public class ExportHelper { /** * Show dialog where to export keys */ - public void showExportKeysDialog(final long[] masterKeyIds, final int keyType, - final String exportFilename, final String checkboxString) { + public void showExportKeysDialog(final long[] masterKeyIds, final String exportFilename, + final boolean showSecretCheckbox) { mExportFilename = exportFilename; // Message is received after file is selected @@ -71,14 +71,9 @@ 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); - if (data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED)) { - type = Id.type.public_secret_key; - } - - exportKeys(masterKeyIds, type); + exportKeys(masterKeyIds, data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED)); } } }; @@ -98,9 +93,11 @@ public class ExportHelper { } String message = mActivity.getString(R.string.specify_file_to_export_to); + String checkMsg = showSecretCheckbox ? + mActivity.getString(R.string.also_export_secret_keys) : null; mFileDialog = FileDialogFragment.newInstance(messenger, title, message, - exportFilename, checkboxString); + exportFilename, checkMsg); mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog"); } @@ -110,7 +107,7 @@ public class ExportHelper { /** * Export keys */ - public void exportKeys(long[] masterKeyIds, int keyType) { + public void exportKeys(long[] masterKeyIds, boolean exportSecret) { Log.d(Constants.TAG, "exportKeys started"); // Send all information needed to service to export key in other thread @@ -122,7 +119,7 @@ public class ExportHelper { Bundle data = new Bundle(); data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename); - data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType); + data.putBoolean(KeychainIntentService.EXPORT_SECRET, exportSecret); if (masterKeyIds == null) { data.putBoolean(KeychainIntentService.EXPORT_ALL, true); 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 768237c7d..1c6aa7971 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 @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.service; import android.app.IntentService; import android.content.Intent; +import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Message; @@ -50,6 +51,8 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.util.HkpKeyServer; @@ -147,7 +150,7 @@ public class KeychainIntentService extends IntentService // export key public static final String EXPORT_OUTPUT_STREAM = "export_output_stream"; public static final String EXPORT_FILENAME = "export_filename"; - public static final String EXPORT_KEY_TYPE = "export_key_type"; + 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"; @@ -635,19 +638,13 @@ public class KeychainIntentService extends IntentService } else if (ACTION_EXPORT_KEYRING.equals(action)) { try { - /* Input */ - int keyType = Id.type.public_key; - if (data.containsKey(EXPORT_KEY_TYPE)) { - keyType = data.getInt(EXPORT_KEY_TYPE); - } + boolean exportSecret = data.getBoolean(EXPORT_SECRET, false); long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID); String outputFile = data.getString(EXPORT_FILENAME); // If not exporting all keys get the masterKeyIds of the keys to export from the intent boolean exportAll = data.getBoolean(EXPORT_ALL); - /* Operation */ - // check if storage is ready if (!FileHelper.isStorageMounted(outputFile)) { throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready)); @@ -655,31 +652,30 @@ public class KeychainIntentService extends IntentService ArrayList publicMasterKeyIds = new ArrayList(); ArrayList secretMasterKeyIds = new ArrayList(); - // TODO redo - ArrayList allPublicMasterKeyIds = null; // ProviderHelper.getPublicKeyRingsMasterKeyIds(this); - ArrayList allSecretMasterKeyIds = null; // ProviderHelper.getSecretKeyRingsMasterKeyIds(this); - if (exportAll) { - // get all public key ring MasterKey ids - if (keyType == Id.type.public_key || keyType == Id.type.public_secret_key) { - publicMasterKeyIds = allPublicMasterKeyIds; + String selection = null; + if(!exportAll) { + selection = KeychainDatabase.Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + " IN( "; + for(long l : masterKeyIds) { + selection += Long.toString(l) + ","; } - // get all secret key ring MasterKey ids - if (keyType == Id.type.secret_key || keyType == Id.type.public_secret_key) { - secretMasterKeyIds = allSecretMasterKeyIds; - } - } else { + selection = selection.substring(0, selection.length()-1) + " )"; + } - 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); - } - } + Cursor cursor = getContentResolver().query(KeyRings.buildUnifiedKeyRingsUri(), + new String[]{ KeyRings.MASTER_KEY_ID, KeyRings.HAS_SECRET }, + selection, null, null); + try { + 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 { + cursor.close(); } PgpImportExport pgpImportExport = new PgpImportExport(this, this, this); 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 e6fd59d55..167401ac5 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 @@ -339,9 +339,8 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener Toast.makeText(this, R.string.error_save_first, Toast.LENGTH_LONG).show(); } else { 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); + mExportHelper.showExportKeysDialog( + new long[] { masterKeyId }, Constants.Path.APP_DIR_FILE_SEC, true); return true; } return true; 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 1f884d7e3..1bc6d4ee1 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 @@ -23,7 +23,6 @@ import android.view.Menu; import android.view.MenuItem; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.ExportHelper; @@ -55,26 +54,20 @@ public class KeyListActivity extends DrawerActivity { switch (item.getItemId()) { case R.id.menu_key_list_import: callIntentForDrawerItem(Constants.DrawerItems.IMPORT_KEYS); - return true; + case R.id.menu_key_list_create: createKey(); - return true; + case R.id.menu_key_list_create_expert: createKeyExpert(); - return true; - case R.id.menu_key_list_export_public: - mExportHelper.showExportKeysDialog(null, - Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB, null); + case R.id.menu_key_list_export: + mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE_PUB, true); return true; - case R.id.menu_key_list_secret_export: - mExportHelper.showExportKeysDialog(null, Id.type.secret_key, - Constants.Path.APP_DIR_FILE_SEC, null); - return true; default: return super.onOptionsItemSelected(item); } 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 33ccd3a23..1d8f7c8ad 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 @@ -60,7 +60,6 @@ import org.sufficientlysecure.keychain.helper.ExportHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.util.Log; @@ -68,7 +67,6 @@ import se.emilsjolander.stickylistheaders.ApiLevelTooLowException; import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; -import java.util.ArrayList; import java.util.HashMap; /** @@ -194,10 +192,8 @@ public class KeyListFragment extends Fragment case R.id.menu_key_list_multi_export: { ids = mAdapter.getCurrentSelectedMasterKeyIds(); ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity()); - mExportHelper - .showExportKeysDialog(ids, Id.type.public_key, - Constants.Path.APP_DIR_FILE_PUB, - getString(R.string.also_export_secret_keys)); + mExportHelper.showExportKeysDialog( + ids, Constants.Path.APP_DIR_FILE_PUB, mAdapter.isAnySecretSelected()); break; } case R.id.menu_key_list_multi_select_all: { @@ -525,6 +521,13 @@ public class KeyListFragment extends Fragment } + public boolean isSecretAvailable(int id) { + if (!mCursor.moveToPosition(id)) { + throw new IllegalStateException("couldn't move cursor to position " + id); + } + + return mCursor.getInt(INDEX_HAS_SECRET) != 0; + } public long getMasterKeyId(int id) { if (!mCursor.moveToPosition(id)) { throw new IllegalStateException("couldn't move cursor to position " + id); @@ -633,6 +636,14 @@ public class KeyListFragment extends Fragment notifyDataSetChanged(); } + public boolean isAnySecretSelected() { + for (int pos : mSelection.keySet()) { + if(mAdapter.isSecretAvailable(pos)) + return true; + } + return false; + } + public long[] getCurrentSelectedMasterKeyIds() { long[] ids = new long[mSelection.size()]; int i = 0; 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 af1fcfe52..7b9ba4b2d 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 @@ -42,7 +42,6 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter; import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; -import org.sufficientlysecure.keychain.util.Log; import java.util.ArrayList; @@ -120,10 +119,12 @@ public class ViewKeyActivity extends ActionBarActivity { uploadToKeyserver(mDataUri); return true; case R.id.menu_key_view_export_file: - long masterKeyId = Long.valueOf(mDataUri.getLastPathSegment()); - long[] ids = new long[]{masterKeyId}; - mExportHelper.showExportKeysDialog(ids, Id.type.public_key, - Constants.Path.APP_DIR_FILE_PUB, null); + long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri); + mExportHelper.showExportKeysDialog( + new long[] { masterKeyId } , Constants.Path.APP_DIR_FILE_PUB, + // TODO this doesn't work? + ((ViewKeyMainFragment) mTabsAdapter.getItem(0)).isSecretAvailable() + ); return true; case R.id.menu_key_view_share_default_fingerprint: shareKey(mDataUri, true); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index 3c6ae514e..830c5fcae 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -81,6 +81,9 @@ public class ViewKeyMainFragment extends Fragment implements private Uri mDataUri; + // for activity + private boolean mSecretAvailable = false; + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.view_key_main_fragment, container, false); @@ -227,9 +230,9 @@ public class ViewKeyMainFragment extends Fragment implements mEmail.setText(mainUserId[1]); mComment.setText(mainUserId[2]); - if (data.getInt(INDEX_UNIFIED_HAS_SECRET) > 0) { - // set this attribute. this is a LITTLE unclean, but we have the info available - // right here, so why not. + if (data.getInt(INDEX_UNIFIED_HAS_SECRET) != 0) { + mSecretAvailable = true; + mSecretKey.setTextColor(getResources().getColor(R.color.emphasis)); mSecretKey.setText(R.string.secret_key_yes); @@ -244,6 +247,8 @@ public class ViewKeyMainFragment extends Fragment implements } }); } else { + mSecretAvailable = false; + mSecretKey.setTextColor(Color.BLACK); mSecretKey.setText(getResources().getString(R.string.secret_key_no)); @@ -332,6 +337,11 @@ public class ViewKeyMainFragment extends Fragment implements } } + /** Returns true if the key current displayed is known to have a secret key. */ + public boolean isSecretAvailable() { + return mSecretAvailable; + } + private void encryptToContact(Uri dataUri) { // TODO preselect from uri? should be feasible without trivial query long keyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri); diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list.xml b/OpenPGP-Keychain/src/main/res/menu/key_list.xml index bcb2a4b99..b75f4e9a6 100644 --- a/OpenPGP-Keychain/src/main/res/menu/key_list.xml +++ b/OpenPGP-Keychain/src/main/res/menu/key_list.xml @@ -38,17 +38,6 @@ app:showAsAction="ifRoom|withText" android:icon="@drawable/ic_action_import_export" android:title="@string/menu_export_keys"> - - - - -