From c725239a69544213229e2d1d0b69b4dca0bcc5d9 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 19 Aug 2014 15:45:42 +0200 Subject: consolidate: split into two steps, can pick up at second step if anything fails --- .../org/sufficientlysecure/keychain/Constants.java | 3 + .../keychain/helper/Preferences.java | 31 +++++++++++ .../keychain/provider/ProviderHelper.java | 65 +++++++++++++++++----- .../keychain/service/KeychainIntentService.java | 13 +---- .../keychain/service/OperationResultParcel.java | 1 + .../keychain/util/FileImportCache.java | 22 +++++++- OpenKeychain/src/main/res/values/strings.xml | 3 + 7 files changed, 112 insertions(+), 26 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index bce093427..78b66464b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -68,6 +68,9 @@ public final class Constants { public static final String KEY_SERVERS_DEFAULT_VERSION = "keyServersDefaultVersion"; public static final String WRITE_VERSION_HEADER = "writeVersionHeader"; public static final String FIRST_TIME = "firstTime"; + public static final String CACHED_CONSOLIDATE = "cachedConsolidate"; + public static final String CACHED_CONSOLIDATE_SECRETS = "cachedConsolidateSecrets"; + public static final String CACHED_CONSOLIDATE_PUBLICS = "cachedConsolidatePublics"; } public static final class Defaults { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java index 14ae46840..9a10148f2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java @@ -25,6 +25,7 @@ import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.openpgp.PGPEncryptedData; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.Constants.Pref; import java.util.ArrayList; import java.util.Arrays; @@ -134,6 +135,36 @@ public class Preferences { editor.commit(); } + public boolean getCachedConsolidate() { + return mSharedPreferences.getBoolean(Pref.CACHED_CONSOLIDATE, false); + } + + public void setCachedConsolidate(boolean value) { + SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.putBoolean(Pref.CACHED_CONSOLIDATE, value); + editor.commit(); + } + + public int getCachedConsolidateNumPublics() { + return mSharedPreferences.getInt(Pref.CACHED_CONSOLIDATE_PUBLICS, 100); + } + + public void setCachedConsolidateNumPublics(int value) { + SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.putInt(Pref.CACHED_CONSOLIDATE_PUBLICS, value); + editor.commit(); + } + + public int getCachedConsolidateNumSecrets() { + return mSharedPreferences.getInt(Pref.CACHED_CONSOLIDATE_SECRETS, 100); + } + + public void setCachedConsolidateNumSecrets(int value) { + SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.putInt(Pref.CACHED_CONSOLIDATE_SECRETS, value); + editor.commit(); + } + public boolean isFirstTime() { return mSharedPreferences.getBoolean(Constants.Pref.FIRST_TIME, true); } 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 3594ded51..5f55eedd5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -28,6 +28,8 @@ import android.os.RemoteException; import android.support.v4.util.LongSparseArray; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; @@ -58,6 +60,7 @@ import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResul import org.sufficientlysecure.keychain.util.FileImportCache; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ProgressFixedScaler; import org.sufficientlysecure.keychain.util.ProgressScaler; import java.io.ByteArrayOutputStream; @@ -823,11 +826,9 @@ public class ProviderHelper { } - public ConsolidateResult consolidateDatabase(Progressable progress) { + public ConsolidateResult consolidateDatabaseStep1(Progressable progress) { // 1a. fetch all secret keyrings into a cache file - int numSecrets, numPublics; - log(LogLevel.START, LogType.MSG_CON, mIndent); mIndent += 1; @@ -836,7 +837,7 @@ public class ProviderHelper { log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_SECRET, mIndent); mIndent += 1; - final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] { + final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{ KeyRings.PRIVKEY_DATA, KeyRings.FINGERPRINT, KeyRings.HAS_ANY_SECRET }, KeyRings.HAS_ANY_SECRET + " = 1", null, null); @@ -844,7 +845,7 @@ public class ProviderHelper { return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog); } - numSecrets = cursor.getCount(); + Preferences.getPreferences(mContext).setCachedConsolidateNumSecrets(cursor.getCount()); FileImportCache cache = new FileImportCache(mContext, "consolidate_secret.pcl"); @@ -894,7 +895,7 @@ public class ProviderHelper { log(LogLevel.DEBUG, LogType.MSG_CON_SAVE_PUBLIC, mIndent); mIndent += 1; - final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[] { + final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{ KeyRings.PUBKEY_DATA, KeyRings.FINGERPRINT }, null, null, null); @@ -902,7 +903,7 @@ public class ProviderHelper { return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog); } - numPublics = cursor.getCount(); + Preferences.getPreferences(mContext).setCachedConsolidateNumSecrets(cursor.getCount()); FileImportCache cache = new FileImportCache(mContext, "consolidate_public.pcl"); @@ -946,19 +947,39 @@ public class ProviderHelper { mIndent -= 1; } + Preferences.getPreferences(mContext).setCachedConsolidate(true); + + return consolidateDatabaseStep2(progress); + } + + public ConsolidateResult consolidateDatabaseStep2(Progressable progress) { + + Preferences prefs = Preferences.getPreferences(mContext); + if ( ! prefs.getCachedConsolidate()) { + log(LogLevel.ERROR, LogType.MSG_CON_ERROR_BAD_STATE); + return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog); + } + + // Set flag that we have a cached consolidation here + int numSecrets = prefs.getCachedConsolidateNumSecrets(); + int numPublics = prefs.getCachedConsolidateNumPublics(); + // 2. wipe database (IT'S DANGEROUS) log(LogLevel.DEBUG, LogType.MSG_CON_DB_CLEAR, mIndent); new KeychainDatabase(mContext).clearDatabase(); + FileImportCache cacheSecret = + new FileImportCache(mContext, "consolidate_secret.pcl"); + FileImportCache cachePublic = + new FileImportCache(mContext, "consolidate_public.pcl"); + // 3. Re-Import secret keyrings from cache try { log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_SECRET, mIndent, numSecrets); mIndent += 1; - FileImportCache cache = - new FileImportCache(mContext, "consolidate_secret.pcl"); - new PgpImportExport(mContext, this, new ProgressScaler(progress, 10, 25, 100)) - .importKeyRings(cache.readCache(), numSecrets); + new PgpImportExport(mContext, this, new ProgressFixedScaler(progress, 10, 25, 100, R.string.progress_con_reimport)) + .importKeyRings(cacheSecret.readCache(false), numSecrets); } catch (IOException e) { Log.e(Constants.TAG, "error importing secret"); return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog); @@ -966,15 +987,13 @@ public class ProviderHelper { mIndent -= 1; } - // 3. Re-Import public keyrings from cache + // 4. Re-Import public keyrings from cache try { log(LogLevel.DEBUG, LogType.MSG_CON_REIMPORT_PUBLIC, mIndent, numPublics); mIndent += 1; - FileImportCache cache = - new FileImportCache(mContext, "consolidate_public.pcl"); new PgpImportExport(mContext, this, new ProgressScaler(progress, 25, 99, 100)) - .importKeyRings(cache.readCache(), numPublics); + .importKeyRings(cachePublic.readCache(false), numPublics); } catch (IOException e) { Log.e(Constants.TAG, "error importing public"); return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, mLog); @@ -982,6 +1001,22 @@ public class ProviderHelper { mIndent -= 1; } + Preferences.getPreferences(mContext).setCachedConsolidate(false); + + // 5. Delete caches + try { + cacheSecret.delete(); + } catch (IOException e) { + // doesn't really matter + Log.e(Constants.TAG, "IOException during delete of secret cache", e); + } + try { + cachePublic.delete(); + } catch (IOException e) { + // doesn't really matter + Log.e(Constants.TAG, "IOException during deletion of public cache", e); + } + progress.setProgress(100, 100); log(LogLevel.OK, LogType.MSG_CON_SUCCESS, mIndent); mIndent -= 1; 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 9f5650df6..2c1bc8463 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -490,10 +490,7 @@ public class KeychainIntentService extends IntentService PgpImportExport pgpImportExport = new PgpImportExport(this, this); ImportKeyResult result = pgpImportExport.importKeyRings(entries); - Bundle resultData = new Bundle(); - resultData.putParcelable(RESULT_IMPORT, result); - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); } catch (Exception e) { sendErrorToHandler(e); } @@ -670,12 +667,8 @@ public class KeychainIntentService extends IntentService } } else if (ACTION_CONSOLIDATE.equals(action)) { - ConsolidateResult result = new ProviderHelper(this).consolidateDatabase(this); - - Bundle resultData = new Bundle(); - resultData.putParcelable(RESULT_CONSOLIDATE, result); - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); + ConsolidateResult result = new ProviderHelper(this).consolidateDatabaseStep1(this); + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java index c601ec57e..3f478cfed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java @@ -391,6 +391,7 @@ public class OperationResultParcel implements Parcelable { // consolidate MSG_CON (R.string.msg_con), + MSG_CON_ERROR_BAD_STATE (R.string.msg_con_error_bad_state), MSG_CON_SAVE_SECRET (R.string.msg_con_save_secret), MSG_CON_SAVE_PUBLIC (R.string.msg_con_save_public), MSG_CON_DB_CLEAR (R.string.msg_con_db_clear), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java index 35833adc6..09275fc95 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileImportCache.java @@ -92,6 +92,10 @@ public class FileImportCache { } public Iterator readCache() throws IOException { + return readCache(true); + } + + public Iterator readCache(final boolean deleteAfterRead) throws IOException { File cacheDir = mContext.getCacheDir(); if (cacheDir == null) { @@ -166,7 +170,10 @@ public class FileImportCache { if (!closed) { try { ois.close(); - tempFile.delete(); + if (deleteAfterRead) { + //noinspection ResultOfMethodCallIgnored + tempFile.delete(); + } } catch (IOException e) { // nvm } @@ -177,4 +184,17 @@ public class FileImportCache { }; } + + public boolean delete() throws IOException { + + File cacheDir = mContext.getCacheDir(); + if (cacheDir == null) { + // https://groups.google.com/forum/#!topic/android-developers/-694j87eXVU + throw new IOException("cache dir is null!"); + } + + final File tempFile = new File(cacheDir, mFilename); + return tempFile.delete(); + } + } diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 8d57f6f2e..e506bf488 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -302,6 +302,8 @@ verifying integrity… deleting \'%s\' securely… + reimporting database… + Name/Email/Key ID… Name/Email/Proof/Key… @@ -671,6 +673,7 @@ Consolidating database + Consolidation started while no database was cached! This is probably a programming error, please file a bug report. Saving secret keyrings Saving public keyrings Clearing database -- cgit v1.2.3 From a2ae318a1adb355efd593b8fd8041d75c25866b3 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 19 Aug 2014 15:55:40 +0200 Subject: add OpenDialogActivity (stub) --- .../keychain/ui/OpenDialogActivity.java | 117 +++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OpenDialogActivity.java (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OpenDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OpenDialogActivity.java new file mode 100644 index 000000000..cdb09bbd0 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OpenDialogActivity.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.support.v4.app.FragmentActivity; +import android.util.Log; +import android.view.ContextThemeWrapper; + +import org.sufficientlysecure.keychain.Constants; + +/** + * We can not directly create a dialog on the context provided inside the content provider. + * This activity encapsulates a DialogFragment to emulate a dialog. + */ +public class OpenDialogActivity extends FragmentActivity { + + public static final String EXTRA_MESSENGER = "messenger"; + public static final String EXTRA_FILENAME = "filename"; + + public static final int MSG_CANCEL = 1; + public static final int MSG_DECRYPT_OPEN = 2; + public static final int MSG_GET_ENCRYPTED = 3; + + MyDialogFragment mDialogFragment; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // this activity itself has no content view (see manifest) + + mDialogFragment = new MyDialogFragment(); + // give all extras through to the fragment + mDialogFragment.setArguments(getIntent().getExtras()); + + mDialogFragment.show(getFragmentManager(), "dialog"); + } + + public static class MyDialogFragment extends DialogFragment { + + private Messenger mMessenger; + + /** + * Creates dialog + */ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + mMessenger = getArguments().getParcelable(EXTRA_MESSENGER); + String filename = getArguments().getString(EXTRA_FILENAME); + + // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay + ContextThemeWrapper context = new ContextThemeWrapper(getActivity(), + android.R.style.Theme_DeviceDefault_Light_Dialog); + ProgressDialog.Builder progress = new ProgressDialog.Builder(context); + return progress.show(); + } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + + dismiss(); + sendMessageToHandler(MSG_CANCEL); + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + Log.d(Constants.TAG, "onDismiss"); + + getActivity().finish(); + } + + /** + * Send message back to handler which is initialized in a activity + * + * @param what Message integer you want to send + */ + private void sendMessageToHandler(Integer what) { + Message msg = Message.obtain(); + msg.what = what; + + 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); + } + } + + } + +} -- cgit v1.2.3 From 0422d48b61011ff75ef6d85a6e45b90aebb5e58b Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 19 Aug 2014 15:55:53 +0200 Subject: add ProgressFixedScaler (forgot in a previous commit) --- .../keychain/util/ProgressFixedScaler.java | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java new file mode 100644 index 000000000..4bb4ca5de --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressFixedScaler.java @@ -0,0 +1,29 @@ +package org.sufficientlysecure.keychain.util; + +import org.sufficientlysecure.keychain.pgp.Progressable; + +/** This is a simple variant of ProgressScaler which shows a fixed progress message, ignoring + * the provided ones. + */ +public class ProgressFixedScaler extends ProgressScaler { + + final int mResId; + + public ProgressFixedScaler(Progressable wrapped, int from, int to, int max, int resId) { + super(wrapped, from, to, max); + mResId = resId; + } + + public void setProgress(int resourceId, int progress, int max) { + if (mWrapped != null) { + mWrapped.setProgress(mResId, mFrom + progress * (mTo - mFrom) / max, mMax); + } + } + + public void setProgress(String message, int progress, int max) { + if (mWrapped != null) { + mWrapped.setProgress(mResId, mFrom + progress * (mTo - mFrom) / max, mMax); + } + } + +} -- cgit v1.2.3 From 9fb1050fed5cdaa238219b29958cba1c484dff7e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 19 Aug 2014 15:56:53 +0200 Subject: stub for consolidate recovery in KeychainApplication --- .../org/sufficientlysecure/keychain/KeychainApplication.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index 9b9880533..233226cc5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -84,11 +84,18 @@ public class KeychainApplication extends Application { setupAccountAsNeeded(this); // Update keyserver list as needed - Preferences.getPreferences(this).updatePreferences(); + Preferences prefs = Preferences.getPreferences(this); + + prefs.updatePreferences(); TlsHelper.addStaticCA("pool.sks-keyservers.net", getAssets(), "sks-keyservers.netCA.cer"); TemporaryStorageProvider.cleanUp(this); + + if (prefs.getCachedConsolidate()) { + // do something which calls ProviderHelper.consolidateDatabaseStep2 with a progressable + } + } public static void setupAccountAsNeeded(Context context) { -- cgit v1.2.3