diff options
10 files changed, 266 insertions, 27 deletions
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/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) { 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<ParcelableKeyRing> cache =                      new FileImportCache<ParcelableKeyRing>(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<ParcelableKeyRing> cache =                      new FileImportCache<ParcelableKeyRing>(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<ParcelableKeyRing> cacheSecret = +                new FileImportCache<ParcelableKeyRing>(mContext, "consolidate_secret.pcl"); +        FileImportCache<ParcelableKeyRing> cachePublic = +                new FileImportCache<ParcelableKeyRing>(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<ParcelableKeyRing> cache = -                    new FileImportCache<ParcelableKeyRing>(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<ParcelableKeyRing> cache = -                    new FileImportCache<ParcelableKeyRing>(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/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 <dominik@dominikschuermann.de> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +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); +            } +        } + +    } + +} 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<E extends Parcelable> {      }      public Iterator<E> readCache() throws IOException { +        return readCache(true); +    } + +    public Iterator<E> readCache(final boolean deleteAfterRead) throws IOException {          File cacheDir = mContext.getCacheDir();          if (cacheDir == null) { @@ -166,7 +170,10 @@ public class FileImportCache<E extends Parcelable> {                  if (!closed) {                      try {                          ois.close(); -                        tempFile.delete(); +                        if (deleteAfterRead) { +                            //noinspection ResultOfMethodCallIgnored +                            tempFile.delete(); +                        }                      } catch (IOException e) {                          // nvm                      } @@ -177,4 +184,17 @@ public class FileImportCache<E extends Parcelable> {          };      } + +    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/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); +        } +    } + +} 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 @@      <string name="progress_verifying_integrity">verifying integrity…</string>      <string name="progress_deleting_securely">deleting \'%s\' securely…</string> +    <string name="progress_con_reimport">reimporting database…</string> +      <!-- action strings -->      <string name="hint_keyserver_search_hint">Name/Email/Key ID…</string>      <string name="hint_keybase_search_hint">Name/Email/Proof/Key…</string> @@ -671,6 +673,7 @@      <!-- Consolidate -->      <string name="msg_con">Consolidating database</string> +    <string name="msg_con_error_bad_state">Consolidation started while no database was cached! This is probably a programming error, please file a bug report.</string>      <string name="msg_con_save_secret">Saving secret keyrings</string>      <string name="msg_con_save_public">Saving public keyrings</string>      <string name="msg_con_db_clear">Clearing database</string>  | 
