From 6ed0f667cd1d556a923bc7d624f296abe17f795a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 20 Aug 2014 21:29:11 +0200 Subject: [PATCH 1/6] consolidate: remove debug "breakpoint" --- .../sufficientlysecure/keychain/provider/ProviderHelper.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 0d6e83749..47f4682c7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -998,11 +998,6 @@ public class ProviderHelper { log(LogLevel.DEBUG, LogType.MSG_CON_DB_CLEAR); mContentResolver.delete(KeyRings.buildUnifiedKeyRingsUri(), null, null); - // debug: break if this isn't recovery - if (!recovery) { - return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog); - } - FileImportCache cacheSecret = new FileImportCache(mContext, "consolidate_secret.pcl"); FileImportCache cachePublic = From 9122d43d0ab681cfafa67a0b8f81e07776f86083 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 20 Aug 2014 21:51:19 +0200 Subject: [PATCH 2/6] close actionmode in keylist on loading events (avoid inconsistent state) --- .../keychain/ui/KeyListFragment.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index e7b7d2efc..d50ff4331 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -79,6 +79,9 @@ public class KeyListFragment extends LoaderFragment private KeyListAdapter mAdapter; private StickyListHeadersListView mStickyList; + // saves the mode object for multiselect, needed for reset at some point + private ActionMode mActionMode = null; + private String mQuery; private SearchView mSearchView; // empty list layout @@ -148,6 +151,7 @@ public class KeyListFragment extends LoaderFragment public boolean onCreateActionMode(ActionMode mode, Menu menu) { android.view.MenuInflater inflater = getActivity().getMenuInflater(); inflater.inflate(R.menu.key_list_multi, menu); + mActionMode = mode; return true; } @@ -193,6 +197,7 @@ public class KeyListFragment extends LoaderFragment @Override public void onDestroyActionMode(ActionMode mode) { + mActionMode = null; mAdapter.clearSelection(); } @@ -288,6 +293,11 @@ public class KeyListFragment extends LoaderFragment // this view is made visible if no data is available mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty)); + // end action mode, if any + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && mActionMode != null) { + mActionMode.finish(); + } + // The list should now be shown. if (isResumed()) { setContentShown(true); From 6c428fa6b58fcaa8f681baa9ec5b98625c9cef91 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 20 Aug 2014 21:51:57 +0200 Subject: [PATCH 3/6] make number of secret keys imported part of ImportResult parcel --- .../sufficientlysecure/keychain/pgp/PgpImportExport.java | 9 ++++++--- .../keychain/service/OperationResults.java | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index fd37112a5..94ff4a1ba 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -139,10 +139,10 @@ public class PgpImportExport { // If there aren't even any keys, do nothing here. if (entries == null || !entries.hasNext()) { return new ImportKeyResult( - ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0); + ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0, 0); } - int newKeys = 0, oldKeys = 0, badKeys = 0; + int newKeys = 0, oldKeys = 0, badKeys = 0, secret = 0; int position = 0; double progSteps = 100.0 / num; @@ -177,6 +177,9 @@ public class PgpImportExport { oldKeys += 1; } else { newKeys += 1; + if (key.isSecret()) { + secret += 1; + } } } catch (IOException e) { @@ -213,7 +216,7 @@ public class PgpImportExport { } } - return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys); + return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys, secret); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java index 878f6ca47..c59a7d172 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java @@ -40,7 +40,7 @@ public abstract class OperationResults { public static class ImportKeyResult extends OperationResultParcel { - public final int mNewKeys, mUpdatedKeys, mBadKeys; + public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret; // At least one new key public static final int RESULT_OK_NEWKEYS = 2; @@ -76,14 +76,16 @@ public abstract class OperationResults { mNewKeys = source.readInt(); mUpdatedKeys = source.readInt(); mBadKeys = source.readInt(); + mSecret = source.readInt(); } public ImportKeyResult(int result, OperationLog log, - int newKeys, int updatedKeys, int badKeys) { + int newKeys, int updatedKeys, int badKeys, int secret) { super(result, log); mNewKeys = newKeys; mUpdatedKeys = updatedKeys; mBadKeys = badKeys; + mSecret = secret; } @Override @@ -92,6 +94,7 @@ public abstract class OperationResults { dest.writeInt(mNewKeys); dest.writeInt(mUpdatedKeys); dest.writeInt(mBadKeys); + dest.writeInt(mSecret); } public static Creator CREATOR = new Creator() { From dd1b27b28f7c84cc10a4dd632b2175d9171f6c72 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 20 Aug 2014 21:52:54 +0200 Subject: [PATCH 4/6] consolidate: small ui things --- .../sufficientlysecure/keychain/provider/ProviderHelper.java | 4 ++++ OpenKeychain/src/main/res/values/strings.xml | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 47f4682c7..717d3c5ba 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -832,6 +832,8 @@ public class ProviderHelper { log(LogLevel.START, LogType.MSG_CON); mIndent += 1; + progress.setProgress(R.string.progress_con_saving, 0, 100); + try { log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_SECRET); @@ -891,6 +893,8 @@ public class ProviderHelper { mIndent -= 1; } + progress.setProgress(R.string.progress_con_saving, 3, 100); + // 1b. fetch all public keyrings into a cache file try { diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 71f4504d7..c4697cac3 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -302,7 +302,8 @@ verifying integrity… deleting \'%s\' securely… - reimporting database… + consolidate: saving to cache… + consolidate: reimporting… Name/Email/Key ID… From dcf268bcb2cbe433fdef8af4fd516a6482ac268a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 20 Aug 2014 23:08:52 +0200 Subject: [PATCH 5/6] move key deletion into KeychainIntentHandler --- .../service/KeychainIntentService.java | 50 ++++++++++- .../keychain/ui/ViewKeyActivity.java | 8 +- .../ui/dialog/DeleteKeyDialogFragment.java | 85 +++++++++++-------- OpenKeychain/src/main/res/values/strings.xml | 1 + 4 files changed, 104 insertions(+), 40 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index d568df91a..4330a1c01 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -49,6 +49,7 @@ import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -104,6 +105,8 @@ public class KeychainIntentService extends IntentService public static final String ACTION_CERTIFY_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING"; + public static final String ACTION_DELETE = Constants.INTENT_PREFIX + "DELETE"; + public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE"; /* keys for data bundle */ @@ -143,6 +146,10 @@ public class KeychainIntentService extends IntentService // delete file securely public static final String DELETE_FILE = "deleteFile"; + // delete keyring(s) + 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_FILE = "import_key_file"; @@ -487,9 +494,14 @@ public class KeychainIntentService extends IntentService entries = cache.readCacheIntoList(); } - PgpImportExport pgpImportExport = new PgpImportExport(this, this); + ProviderHelper providerHelper = new ProviderHelper(this); + PgpImportExport pgpImportExport = new PgpImportExport(this, providerHelper, this); ImportKeyResult result = pgpImportExport.importKeyRings(entries); + if (result.mSecret > 0) { + providerHelper.consolidateDatabaseStep1(this); + } + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); } catch (Exception e) { sendErrorToHandler(e); @@ -666,6 +678,42 @@ public class KeychainIntentService extends IntentService sendErrorToHandler(e); } + } else if (ACTION_DELETE.equals(action)) { + + try { + + long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST); + boolean isSecret = data.getBoolean(DELETE_IS_SECRET); + + if (masterKeyIds.length == 0) { + throw new PgpGeneralException("List of keys to delete is empty"); + } + + if (isSecret && masterKeyIds.length > 1) { + throw new PgpGeneralException("Secret keys can only be deleted individually!"); + } + + boolean success = false; + for (long masterKeyId : masterKeyIds) { + int count = getContentResolver().delete( + KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null + ); + success |= count > 0; + } + + if (isSecret && success) { + ConsolidateResult result = + new ProviderHelper(this).consolidateDatabaseStep1(this); + } + + if (success) { + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); + } + + } catch (Exception e) { + sendErrorToHandler(e); + } + } else if (ACTION_CONSOLIDATE.equals(action)) { ConsolidateResult result; if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index c9db79740..2c0881ea4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -54,6 +54,8 @@ import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; 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.service.OperationResultParcel; import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout; @@ -303,8 +305,10 @@ public class ViewKeyActivity extends ActionBarActivity implements Handler returnHandler = new Handler() { @Override public void handleMessage(Message message) { - setResult(RESULT_CANCELED); - finish(); + if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { + setResult(RESULT_CANCELED); + finish(); + } } }; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java index 4927a4d24..d0c9cea5b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java @@ -18,7 +18,9 @@ package org.sufficientlysecure.keychain.ui.dialog; import android.app.Dialog; +import android.app.ProgressDialog; import android.content.DialogInterface; +import android.content.Intent; import android.os.Bundle; import android.os.Message; import android.os.Messenger; @@ -31,9 +33,10 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.util.Log; import java.util.HashMap; @@ -48,8 +51,6 @@ public class DeleteKeyDialogFragment extends DialogFragment { private TextView mMainMessage; private View mInflateView; - private Messenger mMessenger; - /** * Creates new instance of this delete file dialog fragment */ @@ -68,7 +69,7 @@ public class DeleteKeyDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final FragmentActivity activity = getActivity(); - mMessenger = getArguments().getParcelable(ARG_MESSENGER); + final Messenger messenger = getArguments().getParcelable(ARG_MESSENGER); final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS); @@ -83,6 +84,8 @@ public class DeleteKeyDialogFragment extends DialogFragment { builder.setTitle(R.string.warning); + final boolean hasSecret; + // If only a single key has been selected if (masterKeyIds.length == 1) { long masterKeyId = masterKeyIds[0]; @@ -98,7 +101,7 @@ public class DeleteKeyDialogFragment extends DialogFragment { } ); String userId = (String) data.get(KeyRings.USER_ID); - boolean hasSecret = ((Long) data.get(KeyRings.HAS_ANY_SECRET)) == 1; + hasSecret = ((Long) data.get(KeyRings.HAS_ANY_SECRET)) == 1; // Set message depending on which key it is. mMainMessage.setText(getString( @@ -107,12 +110,12 @@ public class DeleteKeyDialogFragment extends DialogFragment { userId )); } catch (ProviderHelper.NotFoundException e) { - sendMessageToHandler(MESSAGE_ERROR, null); dismiss(); return null; } } else { mMainMessage.setText(R.string.key_deletion_confirmation_multi); + hasSecret = false; } builder.setIcon(R.drawable.ic_dialog_alert_holo_light); @@ -120,18 +123,45 @@ public class DeleteKeyDialogFragment extends DialogFragment { @Override public void onClick(DialogInterface dialog, int which) { - boolean success = false; - for (long masterKeyId : masterKeyIds) { - int count = activity.getContentResolver().delete( - KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null - ); - success = count > 0; - } - if (success) { - sendMessageToHandler(MESSAGE_OKAY, null); - } else { - sendMessageToHandler(MESSAGE_ERROR, null); - } + // Send all information needed to service to import key in other thread + Intent intent = new Intent(getActivity(), KeychainIntentService.class); + + intent.setAction(KeychainIntentService.ACTION_DELETE); + + // Message is received after importing is done in KeychainIntentService + KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( + getActivity(), + getString(R.string.progress_deleting), + ProgressDialog.STYLE_HORIZONTAL) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + 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(KeychainIntentService.DELETE_KEY_LIST, masterKeyIds); + data.putBoolean(KeychainIntentService.DELETE_IS_SECRET, hasSecret); + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(saveHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // show progress dialog + saveHandler.showProgressDialog(getActivity()); + + // start service with intent + getActivity().startService(intent); + dismiss(); } }); @@ -146,23 +176,4 @@ public class DeleteKeyDialogFragment extends DialogFragment { return builder.show(); } - /** - * Send message back to handler which is initialized in a activity - * - * @param what Message integer you want to send - */ - private void sendMessageToHandler(Integer what, Bundle data) { - Message msg = Message.obtain(); - msg.what = what; - if (data != null) { - msg.setData(data); - } - try { - mMessenger.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); - } - } } diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index c4697cac3..fede86b1c 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -301,6 +301,7 @@ decompressing data… verifying integrity… deleting \'%s\' securely… + deleting keys… consolidate: saving to cache… consolidate: reimporting… From 9c9fc5330a402fb873708b998dac5f1ebf54b71c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 20 Aug 2014 23:09:20 +0200 Subject: [PATCH 6/6] small change to make android studio recognize a honeycomb-only block --- .../org/sufficientlysecure/keychain/ui/KeyListFragment.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 6a4039e98..96a332d3e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -292,8 +292,10 @@ public class KeyListFragment extends LoaderFragment mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty)); // end action mode, if any - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && mActionMode != null) { - mActionMode.finish(); + if (mActionMode != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + mActionMode.finish(); + } } // The list should now be shown.