From aef6e6614e19983732216c2c968a1faa4023109f Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 20 Feb 2017 16:28:30 +0100 Subject: [PATCH] extract DatabaseReadWriteInteractor --- .../keychain/TestHelpers.java | 4 +- .../keychain/actions/CustomActions.java | 4 +- .../keychain/operations/BackupOperation.java | 2 +- .../keychain/operations/BaseOperation.java | 9 +- .../operations/BaseReadWriteOperation.java | 30 + .../operations/BenchmarkOperation.java | 4 +- .../keychain/operations/CertifyOperation.java | 8 +- .../operations/ChangeUnlockOperation.java | 10 +- .../operations/ConsolidateOperation.java | 10 +- .../keychain/operations/DeleteOperation.java | 8 +- .../keychain/operations/EditKeyOperation.java | 8 +- .../keychain/operations/ImportOperation.java | 16 +- .../KeybaseVerificationOperation.java | 4 +- .../operations/PromoteKeyOperation.java | 9 +- .../keychain/operations/RevokeOperation.java | 10 +- .../operations/SignEncryptOperation.java | 10 +- .../keychain/operations/UploadOperation.java | 5 +- .../keychain/pgp/CanonicalizedSecretKey.java | 4 +- .../pgp/PgpDecryptVerifyOperation.java | 5 +- .../keychain/pgp/PgpSignEncryptOperation.java | 7 +- .../keychain/pgp/PgpSignatureChecker.java | 5 +- .../provider/CachedPublicKeyRing.java | 24 +- .../keychain/provider/DatabaseInteractor.java | 1371 +---------------- .../provider/DatabaseReadWriteInteractor.java | 1345 ++++++++++++++++ .../keychain/remote/OpenPgpService.java | 6 +- .../ui/RequestKeyPermissionPresenter.java | 3 +- .../keychain/service/KeychainService.java | 33 +- .../service/KeyserverSyncAdapterService.java | 6 +- .../service/PassphraseCacheService.java | 12 +- .../ui/CertifyFingerprintFragment.java | 4 +- .../keychain/ui/CertifyKeyFragment.java | 4 +- .../keychain/ui/CreateKeyActivity.java | 4 +- .../keychain/ui/CreateKeyFinalFragment.java | 4 +- .../keychain/ui/DecryptFragment.java | 4 +- .../keychain/ui/DeleteKeyDialogActivity.java | 9 +- .../keychain/ui/EditIdentitiesFragment.java | 4 +- .../keychain/ui/EditKeyFragment.java | 4 +- .../ui/EncryptModeAsymmetricFragment.java | 3 +- .../keychain/ui/KeyListFragment.java | 3 +- .../keychain/ui/PassphraseDialogActivity.java | 9 +- .../keychain/ui/QrCodeViewActivity.java | 5 +- .../keychain/ui/SafeSlingerActivity.java | 5 +- .../ui/SecurityTokenOperationActivity.java | 9 +- .../keychain/ui/ViewCertActivity.java | 3 +- .../keychain/ui/ViewKeyActivity.java | 11 +- .../keychain/ui/ViewKeyAdvActivity.java | 3 +- .../keychain/ui/ViewKeyAdvShareFragment.java | 11 +- .../ui/adapter/ImportKeysAdapter.java | 5 +- .../ui/base/BaseSecurityTokenActivity.java | 4 +- .../keychain/ui/linked/LinkedIdWizard.java | 4 +- .../keychain/util/NfcHelper.java | 3 +- .../operations/BackupOperationTest.java | 12 +- .../operations/BenchmarkOperationTest.java | 4 +- .../operations/CertifyOperationTest.java | 22 +- .../operations/PromoteKeyOperationTest.java | 16 +- .../keychain/pgp/InputDataOperationTest.java | 6 +- .../keychain/pgp/PgpEncryptDecryptTest.java | 50 +- .../provider/DatabaseInteractorSaveTest.java | 16 +- .../keychain/provider/InteropTest.java | 2 +- .../remote/KeychainExternalProviderTest.java | 4 +- .../support/DatabaseInteractorStub.java | 5 +- .../support/KeyringTestingHelper.java | 5 +- 62 files changed, 1658 insertions(+), 1571 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseReadWriteOperation.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/DatabaseReadWriteInteractor.java diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/TestHelpers.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/TestHelpers.java index 6d957e6fc..b538dc3dd 100644 --- a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/TestHelpers.java +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/TestHelpers.java @@ -38,8 +38,8 @@ import com.nispok.snackbar.Snackbar; import org.hamcrest.Matcher; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.ProgressScaler; @@ -97,7 +97,7 @@ public class TestHelpers { IteratorWithIOThrow stream = UncachedKeyRing.fromStream( getInstrumentation().getContext().getAssets().open(name)); - DatabaseInteractor helper = new DatabaseInteractor(context); + DatabaseReadWriteInteractor helper = new DatabaseReadWriteInteractor(context); while(stream.hasNext()) { UncachedKeyRing ring = stream.next(); if (ring.isSecret()) { diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/actions/CustomActions.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/actions/CustomActions.java index ee532ab92..78d9477f6 100644 --- a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/actions/CustomActions.java +++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/actions/CustomActions.java @@ -27,7 +27,7 @@ import android.view.View; import com.tokenautocomplete.TokenCompleteTextView; import org.hamcrest.Matcher; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter; import static android.support.test.InstrumentationRegistry.getTargetContext; @@ -37,7 +37,7 @@ public abstract class CustomActions { public static ViewAction tokenEncryptViewAddToken(long keyId) throws Exception { CanonicalizedPublicKeyRing ring = - new DatabaseInteractor(getTargetContext()).getCanonicalizedPublicKeyRing(keyId); + new DatabaseReadWriteInteractor(getTargetContext()).getCanonicalizedPublicKeyRing(keyId); final Object item = new KeyAdapter.KeyItem(ring); return new ViewAction() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java index f8568ee3c..7534ee2bf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java @@ -51,9 +51,9 @@ import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; import org.sufficientlysecure.keychain.service.BackupKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java index ee21eb007..cc0e43a98 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java @@ -17,6 +17,9 @@ package org.sufficientlysecure.keychain.operations; + +import java.util.concurrent.atomic.AtomicBoolean; + import android.content.Context; import android.os.Parcelable; import android.support.annotation.NonNull; @@ -32,9 +35,7 @@ import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.util.Passphrase; -import java.util.concurrent.atomic.AtomicBoolean; - -public abstract class BaseOperation implements PassphraseCacheInterface { +public abstract class BaseOperation implements PassphraseCacheInterface { final public Context mContext; final public Progressable mProgressable; @@ -72,7 +73,7 @@ public abstract class BaseOperation implements Passphrase } public BaseOperation(Context context, DatabaseInteractor databaseInteractor, - Progressable progressable, AtomicBoolean cancelled) { + Progressable progressable, AtomicBoolean cancelled) { mContext = context; mProgressable = progressable; mDatabaseInteractor = databaseInteractor; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseReadWriteOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseReadWriteOperation.java new file mode 100644 index 000000000..2b4524a72 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseReadWriteOperation.java @@ -0,0 +1,30 @@ +package org.sufficientlysecure.keychain.operations; + + +import java.util.concurrent.atomic.AtomicBoolean; + +import android.content.Context; +import android.os.Parcelable; + +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; + + +abstract class BaseReadWriteOperation extends BaseOperation { + final DatabaseReadWriteInteractor mDatabaseReadWriteInteractor; + + BaseReadWriteOperation(Context context, + DatabaseReadWriteInteractor databaseInteractor, + Progressable progressable) { + super(context, databaseInteractor, progressable); + + mDatabaseReadWriteInteractor = databaseInteractor; + } + + BaseReadWriteOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, + Progressable progressable, AtomicBoolean cancelled) { + super(context, databaseInteractor, progressable, cancelled); + + mDatabaseReadWriteInteractor = databaseInteractor; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java index ece2d5487..35a036c3c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java @@ -45,7 +45,7 @@ import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants.OpenKeychainSymm import org.sufficientlysecure.keychain.pgp.PgpSignEncryptData; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.BenchmarkInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.util.Log; @@ -55,7 +55,7 @@ import org.sufficientlysecure.keychain.util.ProgressScaler; public class BenchmarkOperation extends BaseOperation { - public BenchmarkOperation(Context context, DatabaseInteractor databaseInteractor, Progressable + public BenchmarkOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, Progressable progressable) { super(context, databaseInteractor, progressable); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java index 17d30f75f..a3fb6aca4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java @@ -39,8 +39,8 @@ import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.provider.DatabaseInteractor.NotFoundException; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; @@ -60,9 +60,9 @@ import org.sufficientlysecure.keychain.util.Passphrase; * * @see CertifyActionsParcel */ -public class CertifyOperation extends BaseOperation { +public class CertifyOperation extends BaseReadWriteOperation { - public CertifyOperation(Context context, DatabaseInteractor databaseInteractor, Progressable progressable, AtomicBoolean + public CertifyOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, Progressable progressable, AtomicBoolean cancelled) { super(context, databaseInteractor, progressable, cancelled); } @@ -223,7 +223,7 @@ public class CertifyOperation extends BaseOperation { KeyFormattingUtils.convertKeyIdToHex(certifiedKey.getMasterKeyId())); // store the signed key in our local cache mDatabaseInteractor.clearLog(); - SaveKeyringResult result = mDatabaseInteractor.savePublicKeyRing(certifiedKey); + SaveKeyringResult result = mDatabaseReadWriteInteractor.savePublicKeyRing(certifiedKey); if (uploadOperation != null) { UploadKeyringParcel uploadInput = diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ChangeUnlockOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ChangeUnlockOperation.java index 4cf76e5a3..bf6ef7923 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ChangeUnlockOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ChangeUnlockOperation.java @@ -29,16 +29,16 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ProgressScaler; -public class ChangeUnlockOperation extends BaseOperation { +public class ChangeUnlockOperation extends BaseReadWriteOperation { - public ChangeUnlockOperation(Context context, DatabaseInteractor databaseInteractor, Progressable progressable) { + public ChangeUnlockOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, Progressable progressable) { super(context, databaseInteractor, progressable); } @@ -71,7 +71,7 @@ public class ChangeUnlockOperation extends BaseOperation { log.add(modifyResult, 1); return new EditKeyResult(log, modifyResult); } - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { log.add(OperationResult.LogType.MSG_ED_ERROR_KEY_NOT_FOUND, 2); return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null); } @@ -90,7 +90,7 @@ public class ChangeUnlockOperation extends BaseOperation { // It's a success, so this must be non-null now UncachedKeyRing ring = modifyResult.getRing(); - SaveKeyringResult saveResult = mDatabaseInteractor + SaveKeyringResult saveResult = mDatabaseReadWriteInteractor .saveSecretKeyRing(ring, new ProgressScaler(mProgressable, 70, 95, 100)); log.add(saveResult, 1); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ConsolidateOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ConsolidateOperation.java index 1142b085e..63fda571c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ConsolidateOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ConsolidateOperation.java @@ -24,13 +24,13 @@ import android.support.annotation.NonNull; import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; import org.sufficientlysecure.keychain.pgp.Progressable; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.ConsolidateInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -public class ConsolidateOperation extends BaseOperation { +public class ConsolidateOperation extends BaseReadWriteOperation { - public ConsolidateOperation(Context context, DatabaseInteractor databaseInteractor, Progressable + public ConsolidateOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, Progressable progressable) { super(context, databaseInteractor, progressable); } @@ -40,9 +40,9 @@ public class ConsolidateOperation extends BaseOperation public ConsolidateResult execute(ConsolidateInputParcel consolidateInputParcel, CryptoInputParcel cryptoInputParcel) { if (consolidateInputParcel.mConsolidateRecovery) { - return mDatabaseInteractor.consolidateDatabaseStep2(mProgressable); + return mDatabaseReadWriteInteractor.consolidateDatabaseStep2(mProgressable); } else { - return mDatabaseInteractor.consolidateDatabaseStep1(mProgressable); + return mDatabaseReadWriteInteractor.consolidateDatabaseStep1(mProgressable); } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java index e86591d6b..33184823e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java @@ -26,8 +26,8 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.service.DeleteKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -41,9 +41,9 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; * a list. * */ -public class DeleteOperation extends BaseOperation { +public class DeleteOperation extends BaseReadWriteOperation { - public DeleteOperation(Context context, DatabaseInteractor databaseInteractor, Progressable progressable) { + public DeleteOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, Progressable progressable) { super(context, databaseInteractor, progressable); } @@ -95,7 +95,7 @@ public class DeleteOperation extends BaseOperation { if (isSecret && success > 0) { log.add(LogType.MSG_DEL_CONSOLIDATE, 1); - ConsolidateResult sub = mDatabaseInteractor.consolidateDatabaseStep1(mProgressable); + ConsolidateResult sub = mDatabaseReadWriteInteractor.consolidateDatabaseStep1(mProgressable); log.add(sub, 2); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java index ab4e95fcc..09469cd40 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -35,8 +35,8 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.provider.DatabaseInteractor.NotFoundException; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.UploadKeyringParcel; @@ -55,9 +55,9 @@ import org.sufficientlysecure.keychain.util.ProgressScaler; * @see SaveKeyringParcel * */ -public class EditKeyOperation extends BaseOperation { +public class EditKeyOperation extends BaseReadWriteOperation { - public EditKeyOperation(Context context, DatabaseInteractor databaseInteractor, + public EditKeyOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, Progressable progressable, AtomicBoolean cancelled) { super(context, databaseInteractor, progressable, cancelled); } @@ -161,7 +161,7 @@ public class EditKeyOperation extends BaseOperation { } // Save the new keyring. - SaveKeyringResult saveResult = mDatabaseInteractor + SaveKeyringResult saveResult = mDatabaseReadWriteInteractor .saveSecretKeyRing(ring, new ProgressScaler(mProgressable, 60, 95, 100)); log.add(saveResult, 1); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java index 4757d7874..668392111 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java @@ -39,7 +39,7 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -80,18 +80,18 @@ import java.util.concurrent.atomic.AtomicBoolean; * method here will generally import keyrings in the order given by the * iterator, so this should be ensured beforehand. */ -public class ImportOperation extends BaseOperation { +public class ImportOperation extends BaseReadWriteOperation { private static final int MAX_THREADS = 10; public static final String CACHE_FILE_NAME = "key_import.pcl"; - public ImportOperation(Context context, DatabaseInteractor databaseInteractor, Progressable + public ImportOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, Progressable progressable) { super(context, databaseInteractor, progressable); } - public ImportOperation(Context context, DatabaseInteractor databaseInteractor, + public ImportOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, Progressable progressable, AtomicBoolean cancelled) { super(context, databaseInteractor, progressable, cancelled); } @@ -319,10 +319,10 @@ public class ImportOperation extends BaseOperation { ProgressScaler progressScaler = new ProgressScaler(progressable, (int) (position * progSteps), (int) ((position + 1) * progSteps), 100); if (key.isSecret()) { - result = mDatabaseInteractor.saveSecretKeyRing(key, progressScaler, + result = mDatabaseReadWriteInteractor.saveSecretKeyRing(key, progressScaler, canKeyRings, skipSave); } else { - result = mDatabaseInteractor.savePublicKeyRing(key, progressScaler, + result = mDatabaseReadWriteInteractor.savePublicKeyRing(key, progressScaler, entry.mExpectedFingerprint, canKeyRings, skipSave); } } @@ -343,7 +343,7 @@ public class ImportOperation extends BaseOperation { // synonymous to isDownloadFromKeyserver. // If no byte data was supplied, import from keyserver took place // this prevents file imports being noted as keyserver imports - mDatabaseInteractor.renewKeyLastUpdatedTime(key.getMasterKeyId(), + mDatabaseReadWriteInteractor.renewKeyLastUpdatedTime(key.getMasterKeyId(), GregorianCalendar.getInstance().getTimeInMillis(), TimeUnit.MILLISECONDS); } @@ -366,7 +366,7 @@ public class ImportOperation extends BaseOperation { setPreventCancel(); ConsolidateResult result; synchronized (mDatabaseInteractor) { - result = mDatabaseInteractor.consolidateDatabaseStep1(progressable); + result = mDatabaseReadWriteInteractor.consolidateDatabaseStep1(progressable); } log.add(result, 1); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java index 4f4a8b0db..8eabfc9f7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java @@ -36,7 +36,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation; import org.sufficientlysecure.keychain.pgp.Progressable; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -59,7 +59,7 @@ import de.measite.minidns.record.TXT; public class KeybaseVerificationOperation extends BaseOperation { - public KeybaseVerificationOperation(Context context, DatabaseInteractor databaseInteractor, + public KeybaseVerificationOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, Progressable progressable) { super(context, databaseInteractor, progressable); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java index 13141b403..55d243a0c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java @@ -33,8 +33,8 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.provider.DatabaseInteractor.NotFoundException; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.PromoteKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -47,9 +47,8 @@ import org.sufficientlysecure.keychain.util.ProgressScaler; * without secret key material, using a GNU_DUMMY s2k type. * */ -public class PromoteKeyOperation extends BaseOperation { - - public PromoteKeyOperation(Context context, DatabaseInteractor databaseInteractor, +public class PromoteKeyOperation extends BaseReadWriteOperation { + public PromoteKeyOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, Progressable progressable, AtomicBoolean cancelled) { super(context, databaseInteractor, progressable, cancelled); } @@ -114,7 +113,7 @@ public class PromoteKeyOperation extends BaseOperation { setPreventCancel(); // Save the new keyring. - SaveKeyringResult saveResult = mDatabaseInteractor + SaveKeyringResult saveResult = mDatabaseReadWriteInteractor .saveSecretKeyRing(promotedRing, new ProgressScaler(mProgressable, 60, 95, 100)); log.add(saveResult, 1); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java index 920efb1ef..33b6cb478 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java @@ -31,17 +31,17 @@ import org.sufficientlysecure.keychain.operations.results.RevokeResult; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.RevokeKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; -public class RevokeOperation extends BaseOperation { +public class RevokeOperation extends BaseReadWriteOperation { - public RevokeOperation(Context context, DatabaseInteractor databaseInteractor, Progressable progressable) { + public RevokeOperation(Context context, DatabaseReadWriteInteractor databaseInteractor, Progressable progressable) { super(context, databaseInteractor, progressable); } @@ -81,7 +81,7 @@ public class RevokeOperation extends BaseOperation { saveKeyringParcel.mRevokeSubKeys.add(masterKeyId); EditKeyResult revokeAndUploadResult = new EditKeyOperation(mContext, - mDatabaseInteractor, mProgressable, mCancelled).execute(saveKeyringParcel, cryptoInputParcel); + mDatabaseReadWriteInteractor, mProgressable, mCancelled).execute(saveKeyringParcel, cryptoInputParcel); if (revokeAndUploadResult.isPending()) { return revokeAndUploadResult; @@ -97,7 +97,7 @@ public class RevokeOperation extends BaseOperation { return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId); } - } catch (PgpKeyNotFoundException | DatabaseInteractor.NotFoundException e) { + } catch (PgpKeyNotFoundException | DatabaseReadWriteInteractor.NotFoundException e) { Log.e(Constants.TAG, "could not find key to revoke", e); log.add(OperationResult.LogType.MSG_REVOKE_ERROR_KEY_FAIL, 1); return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java index fb5c941fb..4a992dc0a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java @@ -18,6 +18,10 @@ package org.sufficientlysecure.keychain.operations; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; + import android.content.Context; import android.net.Uri; import android.support.annotation.NonNull; @@ -36,15 +40,11 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; -import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenSignOperationsBuilder; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenSignOperationsBuilder; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressScaler; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicBoolean; - /** * This is a high-level operation, which encapsulates one or more sign/encrypt diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java index bc75d0ae7..f5c39d3da 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java @@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.UploadKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -59,7 +60,7 @@ import java.util.concurrent.atomic.AtomicBoolean; public class UploadOperation extends BaseOperation { public UploadOperation(Context context, DatabaseInteractor databaseInteractor, - Progressable progressable, AtomicBoolean cancelled) { + Progressable progressable, AtomicBoolean cancelled) { super(context, databaseInteractor, progressable, cancelled); } @@ -132,7 +133,7 @@ public class UploadOperation extends BaseOperation { log.add(LogType.MSG_UPLOAD_KEY, 0, KeyFormattingUtils.convertKeyIdToHex(canonicalizedRing.getMasterKeyId())); return (CanonicalizedPublicKeyRing) canonicalizedRing; - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { log.add(LogType.MSG_UPLOAD_ERROR_NOT_FOUND, 1); return null; } catch (IOException | PgpGeneralException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index ee8a2b050..06a9e8bbe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -47,7 +47,7 @@ import org.bouncycastle.openpgp.operator.jcajce.SessionKeySecretKeyDecryptorBuil import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; @@ -127,7 +127,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { * passphrase in the process. * * This method can potentially take a LONG time (i.e. seconds), so it should only - * ever be called by {@link DatabaseInteractor} for the purpose of caching its output + * ever be called by {@link DatabaseReadWriteInteractor} for the purpose of caching its output * in the database. */ public SecretKeyType getSecretKeyTypeSuperExpensive() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java index b7662b44e..953c7d695 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java @@ -71,8 +71,9 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -668,7 +669,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation 0; - } catch(DatabaseInteractor.NotFoundException e) { + } catch(DatabaseReadWriteInteractor.NotFoundException e) { throw new PgpKeyNotFoundException(e); } } @@ -162,7 +162,7 @@ public class CachedPublicKeyRing extends KeyRing { KeychainContract.KeyRings.HAS_CERTIFY, DatabaseInteractor.FIELD_TYPE_NULL); return !((Boolean) data); - } catch(DatabaseInteractor.NotFoundException e) { + } catch(DatabaseReadWriteInteractor.NotFoundException e) { throw new PgpKeyNotFoundException(e); } } @@ -174,7 +174,7 @@ public class CachedPublicKeyRing extends KeyRing { KeyRings.HAS_ENCRYPT, DatabaseInteractor.FIELD_TYPE_INTEGER); return (Long) data; - } catch(DatabaseInteractor.NotFoundException e) { + } catch(DatabaseReadWriteInteractor.NotFoundException e) { throw new PgpKeyNotFoundException(e); } } @@ -196,7 +196,7 @@ public class CachedPublicKeyRing extends KeyRing { KeyRings.HAS_SIGN, DatabaseInteractor.FIELD_TYPE_INTEGER); return (Long) data; - } catch(DatabaseInteractor.NotFoundException e) { + } catch(DatabaseReadWriteInteractor.NotFoundException e) { throw new PgpKeyNotFoundException(e); } } @@ -208,7 +208,7 @@ public class CachedPublicKeyRing extends KeyRing { KeychainContract.KeyRings.VERIFIED, DatabaseInteractor.FIELD_TYPE_INTEGER); return ((Long) data).intValue(); - } catch(DatabaseInteractor.NotFoundException e) { + } catch(DatabaseReadWriteInteractor.NotFoundException e) { throw new PgpKeyNotFoundException(e); } } @@ -219,7 +219,7 @@ public class CachedPublicKeyRing extends KeyRing { KeychainContract.KeyRings.HAS_ANY_SECRET, DatabaseInteractor.FIELD_TYPE_INTEGER); return (Long) data > 0; - } catch(DatabaseInteractor.NotFoundException e) { + } catch(DatabaseReadWriteInteractor.NotFoundException e) { throw new PgpKeyNotFoundException(e); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/DatabaseInteractor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/DatabaseInteractor.java index 1d1b93d93..31b0eb090 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/DatabaseInteractor.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/DatabaseInteractor.java @@ -1,130 +1,58 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * Copyright (C) 2014 Vincent Breitmoser - * - * 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.provider; -import android.content.ContentProviderOperation; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.OperationApplicationException; import android.database.Cursor; import android.net.Uri; -import android.os.RemoteException; -import android.support.annotation.NonNull; -import android.support.v4.util.LongSparseArray; -import org.openintents.openpgp.util.OpenPgpUtils; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; -import org.sufficientlysecure.keychain.operations.ImportOperation; -import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; -import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; -import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; -import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; -import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; -import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; -import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; -import org.sufficientlysecure.keychain.pgp.WrappedSignature; -import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.IteratorWithSize; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.ParcelableFileCache; -import org.sufficientlysecure.keychain.util.Preferences; -import org.sufficientlysecure.keychain.util.ProgressFixedScaler; -import org.sufficientlysecure.keychain.util.ProgressScaler; -import org.sufficientlysecure.keychain.util.Utf8Util; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.TimeUnit; -/** - * This class contains high level methods for database access. Despite its - * name, it is not only a helper but actually the main interface for all - * synchronous database operations. - *

- * Operations in this class write logs. These can be obtained from the - * OperationResultParcel return values directly, but are also accumulated over - * the lifetime of the executing ProviderHelper object unless the resetLog() - * method is called to start a new one specifically. - */ public class DatabaseInteractor { - private final Context mContext; - private final ContentResolver mContentResolver; - private OperationLog mLog; - private int mIndent; + // If we ever switch to api level 11, we can ditch this whole mess! + public static final int FIELD_TYPE_NULL = 1; + // this is called integer to stay coherent with the constants in Cursor (api level 11) + public static final int FIELD_TYPE_INTEGER = 2; + public static final int FIELD_TYPE_FLOAT = 3; + public static final int FIELD_TYPE_STRING = 4; + public static final int FIELD_TYPE_BLOB = 5; - public DatabaseInteractor(Context context) { - this(context, new OperationLog(), 0); + final ContentResolver mContentResolver; + OperationLog mLog; + int mIndent; + + public DatabaseInteractor(ContentResolver contentResolver) { + this(contentResolver, new OperationLog(), 0); } - public DatabaseInteractor(Context context, OperationLog log) { - this(context, log, 0); - } - - public DatabaseInteractor(Context context, OperationLog log, int indent) { - mContext = context; - mContentResolver = context.getContentResolver(); - mLog = log; + public DatabaseInteractor(ContentResolver contentResolver, OperationLog log, int indent) { + mContentResolver = contentResolver; mIndent = indent; + mLog = log; } public OperationLog getLog() { return mLog; } - public static class NotFoundException extends Exception { - public NotFoundException() { - } - - public NotFoundException(String name) { - super(name); - } - } - public void log(LogType type) { if (mLog != null) { mLog.add(type, mIndent); @@ -141,14 +69,6 @@ public class DatabaseInteractor { mLog = new OperationLog(); } - // If we ever switch to api level 11, we can ditch this whole mess! - public static final int FIELD_TYPE_NULL = 1; - // this is called integer to stay coherent with the constants in Cursor (api level 11) - public static final int FIELD_TYPE_INTEGER = 2; - public static final int FIELD_TYPE_FLOAT = 3; - public static final int FIELD_TYPE_STRING = 4; - public static final int FIELD_TYPE_BLOB = 5; - public Object getGenericData(Uri uri, String column, int type) throws NotFoundException { Object result = getGenericData(uri, new String[]{column}, new int[]{type}, null).get(column); if (result == null) { @@ -213,38 +133,6 @@ public class DatabaseInteractor { return getGenericData(KeyRings.buildUnifiedKeyRingUri(masterKeyId), proj, types); } - private LongSparseArray getTrustedMasterKeys() { - Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{ - KeyRings.MASTER_KEY_ID, - // we pick from cache only information that is not easily available from keyrings - KeyRings.HAS_ANY_SECRET, KeyRings.VERIFIED, - // and of course, ring data - KeyRings.PUBKEY_DATA - }, KeyRings.HAS_ANY_SECRET + " = 1", null, null); - - try { - LongSparseArray result = new LongSparseArray<>(); - - if (cursor != null && cursor.moveToFirst()) do { - long masterKeyId = cursor.getLong(0); - int verified = cursor.getInt(2); - byte[] blob = cursor.getBlob(3); - if (blob != null) { - result.put(masterKeyId, - new CanonicalizedPublicKeyRing(blob, verified).getPublicKey()); - } - } while (cursor.moveToNext()); - - return result; - - } finally { - if (cursor != null) { - cursor.close(); - } - } - - } - public long getMasterKeyId(long subKeyId) throws NotFoundException { return (Long) getGenericData(KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(subKeyId), KeyRings.MASTER_KEY_ID, FIELD_TYPE_INTEGER); @@ -327,1204 +215,6 @@ public class DatabaseInteractor { } } - // bits, in order: CESA. make SURE these are correct, we will get bad log entries otherwise!! - static final LogType LOG_TYPES_FLAG_MASTER[] = new LogType[]{ - LogType.MSG_IP_MASTER_FLAGS_XXXX, LogType.MSG_IP_MASTER_FLAGS_CXXX, - LogType.MSG_IP_MASTER_FLAGS_XEXX, LogType.MSG_IP_MASTER_FLAGS_CEXX, - LogType.MSG_IP_MASTER_FLAGS_XXSX, LogType.MSG_IP_MASTER_FLAGS_CXSX, - LogType.MSG_IP_MASTER_FLAGS_XESX, LogType.MSG_IP_MASTER_FLAGS_CESX, - LogType.MSG_IP_MASTER_FLAGS_XXXA, LogType.MSG_IP_MASTER_FLAGS_CXXA, - LogType.MSG_IP_MASTER_FLAGS_XEXA, LogType.MSG_IP_MASTER_FLAGS_CEXA, - LogType.MSG_IP_MASTER_FLAGS_XXSA, LogType.MSG_IP_MASTER_FLAGS_CXSA, - LogType.MSG_IP_MASTER_FLAGS_XESA, LogType.MSG_IP_MASTER_FLAGS_CESA - }; - - // same as above, but for subkeys - static final LogType LOG_TYPES_FLAG_SUBKEY[] = new LogType[]{ - LogType.MSG_IP_SUBKEY_FLAGS_XXXX, LogType.MSG_IP_SUBKEY_FLAGS_CXXX, - LogType.MSG_IP_SUBKEY_FLAGS_XEXX, LogType.MSG_IP_SUBKEY_FLAGS_CEXX, - LogType.MSG_IP_SUBKEY_FLAGS_XXSX, LogType.MSG_IP_SUBKEY_FLAGS_CXSX, - LogType.MSG_IP_SUBKEY_FLAGS_XESX, LogType.MSG_IP_SUBKEY_FLAGS_CESX, - LogType.MSG_IP_SUBKEY_FLAGS_XXXA, LogType.MSG_IP_SUBKEY_FLAGS_CXXA, - LogType.MSG_IP_SUBKEY_FLAGS_XEXA, LogType.MSG_IP_SUBKEY_FLAGS_CEXA, - LogType.MSG_IP_SUBKEY_FLAGS_XXSA, LogType.MSG_IP_SUBKEY_FLAGS_CXSA, - LogType.MSG_IP_SUBKEY_FLAGS_XESA, LogType.MSG_IP_SUBKEY_FLAGS_CESA - }; - - /** - * Saves an UncachedKeyRing of the public variant into the db. - *

- * This method will not delete all previous data for this masterKeyId from the database prior - * to inserting. All public data is effectively re-inserted, secret keyrings are left deleted - * and need to be saved externally to be preserved past the operation. - */ - @SuppressWarnings("unchecked") - private int saveCanonicalizedPublicKeyRing(CanonicalizedPublicKeyRing keyRing, - Progressable progress, boolean selfCertsAreTrusted) { - - // start with ok result - int result = SaveKeyringResult.SAVED_PUBLIC; - - long masterKeyId = keyRing.getMasterKeyId(); - UncachedPublicKey masterKey = keyRing.getPublicKey(); - - ArrayList operations; - try { - - log(LogType.MSG_IP_PREPARE); - mIndent += 1; - - // save all keys and userIds included in keyRing object in database - operations = new ArrayList<>(); - - log(LogType.MSG_IP_INSERT_KEYRING); - { // insert keyring - ContentValues values = new ContentValues(); - values.put(KeyRingData.MASTER_KEY_ID, masterKeyId); - try { - values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded()); - } catch (IOException e) { - log(LogType.MSG_IP_ENCODE_FAIL); - return SaveKeyringResult.RESULT_ERROR; - } - - Uri uri = KeyRingData.buildPublicKeyRingUri(masterKeyId); - operations.add(ContentProviderOperation.newInsert(uri).withValues(values).build()); - } - - log(LogType.MSG_IP_INSERT_SUBKEYS); - progress.setProgress(LogType.MSG_IP_INSERT_SUBKEYS.getMsgId(), 40, 100); - mIndent += 1; - { // insert subkeys - Uri uri = Keys.buildKeysUri(masterKeyId); - int rank = 0; - for (CanonicalizedPublicKey key : keyRing.publicKeyIterator()) { - long keyId = key.getKeyId(); - log(keyId == masterKeyId ? LogType.MSG_IP_MASTER : LogType.MSG_IP_SUBKEY, - KeyFormattingUtils.convertKeyIdToHex(keyId) - ); - mIndent += 1; - - ContentValues values = new ContentValues(); - values.put(Keys.MASTER_KEY_ID, masterKeyId); - values.put(Keys.RANK, rank); - - values.put(Keys.KEY_ID, key.getKeyId()); - values.put(Keys.KEY_SIZE, key.getBitStrength()); - values.put(Keys.KEY_CURVE_OID, key.getCurveOid()); - values.put(Keys.ALGORITHM, key.getAlgorithm()); - values.put(Keys.FINGERPRINT, key.getFingerprint()); - - boolean c = key.canCertify(), e = key.canEncrypt(), s = key.canSign(), a = key.canAuthenticate(); - values.put(Keys.CAN_CERTIFY, c); - values.put(Keys.CAN_ENCRYPT, e); - values.put(Keys.CAN_SIGN, s); - values.put(Keys.CAN_AUTHENTICATE, a); - values.put(Keys.IS_REVOKED, key.isRevoked()); - values.put(Keys.IS_SECURE, key.isSecure()); - - // see above - if (masterKeyId == keyId) { - if (key.getKeyUsage() == null) { - log(LogType.MSG_IP_MASTER_FLAGS_UNSPECIFIED); - } else { - log(LOG_TYPES_FLAG_MASTER[(c ? 1 : 0) + (e ? 2 : 0) + (s ? 4 : 0) + (a ? 8 : 0)]); - } - } else { - if (key.getKeyUsage() == null) { - log(LogType.MSG_IP_SUBKEY_FLAGS_UNSPECIFIED); - } else { - log(LOG_TYPES_FLAG_SUBKEY[(c ? 1 : 0) + (e ? 2 : 0) + (s ? 4 : 0) + (a ? 8 : 0)]); - } - } - - Date creation = key.getCreationTime(); - values.put(Keys.CREATION, creation.getTime() / 1000); - Date expiryDate = key.getExpiryTime(); - if (expiryDate != null) { - values.put(Keys.EXPIRY, expiryDate.getTime() / 1000); - if (key.isExpired()) { - log(keyId == masterKeyId ? - LogType.MSG_IP_MASTER_EXPIRED : LogType.MSG_IP_SUBKEY_EXPIRED, - expiryDate.toString()); - } else { - log(keyId == masterKeyId ? - LogType.MSG_IP_MASTER_EXPIRES : LogType.MSG_IP_SUBKEY_EXPIRES, - expiryDate.toString()); - } - } - - operations.add(ContentProviderOperation.newInsert(uri).withValues(values).build()); - ++rank; - mIndent -= 1; - } - } - mIndent -= 1; - - // get a list of owned secret keys, for verification filtering - LongSparseArray trustedKeys = getTrustedMasterKeys(); - - // classify and order user ids. primary are moved to the front, revoked to the back, - // otherwise the order in the keyfile is preserved. - List uids = new ArrayList<>(); - - if (trustedKeys.size() == 0) { - log(LogType.MSG_IP_UID_CLASSIFYING_ZERO); - } else { - log(LogType.MSG_IP_UID_CLASSIFYING, trustedKeys.size()); - } - mIndent += 1; - for (byte[] rawUserId : masterKey.getUnorderedRawUserIds()) { - String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId); - UserPacketItem item = new UserPacketItem(); - uids.add(item); - OpenPgpUtils.UserId splitUserId = KeyRing.splitUserId(userId); - item.userId = userId; - item.name = splitUserId.name; - item.email = splitUserId.email; - item.comment = splitUserId.comment; - int unknownCerts = 0; - - log(LogType.MSG_IP_UID_PROCESSING, userId); - mIndent += 1; - // look through signatures for this specific key - for (WrappedSignature cert : new IterableIterator<>( - masterKey.getSignaturesForRawId(rawUserId))) { - long certId = cert.getKeyId(); - // self signature - if (certId == masterKeyId) { - - // NOTE self-certificates are already verified during canonicalization, - // AND we know there is at most one cert plus at most one revocation - if (!cert.isRevocation()) { - item.selfCert = cert; - item.isPrimary = cert.isPrimaryUserId(); - } else { - item.selfRevocation = cert; - log(LogType.MSG_IP_UID_REVOKED); - } - continue; - - } - - // do we have a trusted key for this? - if (trustedKeys.indexOfKey(certId) < 0) { - unknownCerts += 1; - continue; - } - - // verify signatures from known private keys - CanonicalizedPublicKey trustedKey = trustedKeys.get(certId); - - try { - cert.init(trustedKey); - // if it doesn't certify, leave a note and skip - if (!cert.verifySignature(masterKey, rawUserId)) { - log(LogType.MSG_IP_UID_CERT_BAD); - continue; - } - - log(cert.isRevocation() - ? LogType.MSG_IP_UID_CERT_GOOD_REVOKE - : LogType.MSG_IP_UID_CERT_GOOD, - KeyFormattingUtils.convertKeyIdToHexShort(trustedKey.getKeyId()) - ); - - // check if there is a previous certificate - WrappedSignature prev = item.trustedCerts.get(cert.getKeyId()); - if (prev != null) { - // if it's newer, skip this one - if (prev.getCreationTime().after(cert.getCreationTime())) { - log(LogType.MSG_IP_UID_CERT_OLD); - continue; - } - // if the previous one was a non-revokable certification, no need to look further - if (!prev.isRevocation() && !prev.isRevokable()) { - log(LogType.MSG_IP_UID_CERT_NONREVOKE); - continue; - } - log(LogType.MSG_IP_UID_CERT_NEW); - } - item.trustedCerts.put(cert.getKeyId(), cert); - - } catch (PgpGeneralException e) { - log(LogType.MSG_IP_UID_CERT_ERROR, - KeyFormattingUtils.convertKeyIdToHex(cert.getKeyId())); - } - - } - - if (unknownCerts > 0) { - log(LogType.MSG_IP_UID_CERTS_UNKNOWN, unknownCerts); - } - mIndent -= 1; - - } - mIndent -= 1; - - ArrayList userAttributes = masterKey.getUnorderedUserAttributes(); - // Don't spam the log if there aren't even any attributes - if (!userAttributes.isEmpty()) { - log(LogType.MSG_IP_UAT_CLASSIFYING); - } - - mIndent += 1; - for (WrappedUserAttribute userAttribute : userAttributes) { - - UserPacketItem item = new UserPacketItem(); - uids.add(item); - item.type = userAttribute.getType(); - item.attributeData = userAttribute.getEncoded(); - - int unknownCerts = 0; - - switch (item.type) { - case WrappedUserAttribute.UAT_IMAGE: - log(LogType.MSG_IP_UAT_PROCESSING_IMAGE); - break; - default: - log(LogType.MSG_IP_UAT_PROCESSING_UNKNOWN); - break; - } - mIndent += 1; - // look through signatures for this specific key - for (WrappedSignature cert : new IterableIterator<>( - masterKey.getSignaturesForUserAttribute(userAttribute))) { - long certId = cert.getKeyId(); - // self signature - if (certId == masterKeyId) { - - // NOTE self-certificates are already verified during canonicalization, - // AND we know there is at most one cert plus at most one revocation - // AND the revocation only exists if there is no newer certification - if (!cert.isRevocation()) { - item.selfCert = cert; - } else { - item.selfRevocation = cert; - log(LogType.MSG_IP_UAT_REVOKED); - } - continue; - - } - - // do we have a trusted key for this? - if (trustedKeys.indexOfKey(certId) < 0) { - unknownCerts += 1; - continue; - } - - // verify signatures from known private keys - CanonicalizedPublicKey trustedKey = trustedKeys.get(certId); - - try { - cert.init(trustedKey); - // if it doesn't certify, leave a note and skip - if (!cert.verifySignature(masterKey, userAttribute)) { - log(LogType.MSG_IP_UAT_CERT_BAD); - continue; - } - - log(cert.isRevocation() - ? LogType.MSG_IP_UAT_CERT_GOOD_REVOKE - : LogType.MSG_IP_UAT_CERT_GOOD, - KeyFormattingUtils.convertKeyIdToHexShort(trustedKey.getKeyId()) - ); - - // check if there is a previous certificate - WrappedSignature prev = item.trustedCerts.get(cert.getKeyId()); - if (prev != null) { - // if it's newer, skip this one - if (prev.getCreationTime().after(cert.getCreationTime())) { - log(LogType.MSG_IP_UAT_CERT_OLD); - continue; - } - // if the previous one was a non-revokable certification, no need to look further - if (!prev.isRevocation() && !prev.isRevokable()) { - log(LogType.MSG_IP_UAT_CERT_NONREVOKE); - continue; - } - log(LogType.MSG_IP_UAT_CERT_NEW); - } - item.trustedCerts.put(cert.getKeyId(), cert); - - } catch (PgpGeneralException e) { - log(LogType.MSG_IP_UAT_CERT_ERROR, - KeyFormattingUtils.convertKeyIdToHex(cert.getKeyId())); - } - - } - - if (unknownCerts > 0) { - log(LogType.MSG_IP_UAT_CERTS_UNKNOWN, unknownCerts); - } - mIndent -= 1; - - } - mIndent -= 1; - - progress.setProgress(LogType.MSG_IP_UID_REORDER.getMsgId(), 65, 100); - log(LogType.MSG_IP_UID_REORDER); - // primary before regular before revoked (see UserIdItem.compareTo) - // this is a stable sort, so the order of keys is otherwise preserved. - Collections.sort(uids); - // iterate and put into db - for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) { - UserPacketItem item = uids.get(userIdRank); - operations.add(buildUserIdOperations(masterKeyId, item, userIdRank)); - - if (item.selfRevocation != null) { - operations.add(buildCertOperations(masterKeyId, userIdRank, item.selfRevocation, - Certs.VERIFIED_SELF)); - // don't bother with trusted certs if the uid is revoked, anyways - continue; - } - - if (item.selfCert == null) { - throw new AssertionError("User ids MUST be self-certified at this point!!"); - } - - operations.add(buildCertOperations(masterKeyId, userIdRank, item.selfCert, - selfCertsAreTrusted ? Certs.VERIFIED_SECRET : Certs.VERIFIED_SELF)); - - // iterate over signatures - for (int i = 0; i < item.trustedCerts.size(); i++) { - WrappedSignature sig = item.trustedCerts.valueAt(i); - // if it's a revocation - if (sig.isRevocation()) { - // don't further process it - continue; - } - // otherwise, build database operation - operations.add(buildCertOperations( - masterKeyId, userIdRank, sig, Certs.VERIFIED_SECRET)); - } - } - - } catch (IOException e) { - log(LogType.MSG_IP_ERROR_IO_EXC); - Log.e(Constants.TAG, "IOException during import", e); - return SaveKeyringResult.RESULT_ERROR; - } finally { - mIndent -= 1; - } - - // before deleting key, retrieve it's last updated time - final int INDEX_MASTER_KEY_ID = 0; - final int INDEX_LAST_UPDATED = 1; - Cursor lastUpdatedCursor = mContentResolver.query( - UpdatedKeys.CONTENT_URI, - new String[]{ - UpdatedKeys.MASTER_KEY_ID, - UpdatedKeys.LAST_UPDATED - }, - UpdatedKeys.MASTER_KEY_ID + " = ?", - new String[]{"" + masterKeyId}, - null - ); - if (lastUpdatedCursor.moveToNext()) { - // there was an entry to re-insert - // this operation must happen after the new key is inserted - ContentValues lastUpdatedEntry = new ContentValues(2); - lastUpdatedEntry.put(UpdatedKeys.MASTER_KEY_ID, - lastUpdatedCursor.getLong(INDEX_MASTER_KEY_ID)); - lastUpdatedEntry.put(UpdatedKeys.LAST_UPDATED, - lastUpdatedCursor.getLong(INDEX_LAST_UPDATED)); - operations.add( - ContentProviderOperation - .newInsert(UpdatedKeys.CONTENT_URI) - .withValues(lastUpdatedEntry) - .build() - ); - } - lastUpdatedCursor.close(); - - try { - // delete old version of this keyRing, which also deletes all keys and userIds on cascade - int deleted = mContentResolver.delete( - KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null); - if (deleted > 0) { - log(LogType.MSG_IP_DELETE_OLD_OK); - result |= SaveKeyringResult.UPDATED; - } else { - log(LogType.MSG_IP_DELETE_OLD_FAIL); - } - - log(LogType.MSG_IP_APPLY_BATCH); - progress.setProgress(LogType.MSG_IP_APPLY_BATCH.getMsgId(), 75, 100); - mContentResolver.applyBatch(KeychainContract.CONTENT_AUTHORITY, operations); - - log(LogType.MSG_IP_SUCCESS); - progress.setProgress(LogType.MSG_IP_SUCCESS.getMsgId(), 90, 100); - return result; - - } catch (RemoteException e) { - log(LogType.MSG_IP_ERROR_REMOTE_EX); - Log.e(Constants.TAG, "RemoteException during import", e); - return SaveKeyringResult.RESULT_ERROR; - } catch (OperationApplicationException e) { - log(LogType.MSG_IP_ERROR_OP_EXC); - Log.e(Constants.TAG, "OperationApplicationException during import", e); - return SaveKeyringResult.RESULT_ERROR; - } - - } - - private static class UserPacketItem implements Comparable { - Integer type; - String userId; - String name; - String email; - String comment; - byte[] attributeData; - boolean isPrimary = false; - WrappedSignature selfCert; - WrappedSignature selfRevocation; - LongSparseArray trustedCerts = new LongSparseArray<>(); - - @Override - public int compareTo(@NonNull UserPacketItem o) { - // revoked keys always come last! - //noinspection DoubleNegation - if ((selfRevocation != null) != (o.selfRevocation != null)) { - return selfRevocation != null ? 1 : -1; - } - // if one is a user id, but the other isn't, the user id always comes first. - // we compare for null values here, so != is the correct operator! - // noinspection NumberEquality - if (type != o.type) { - return type == null ? -1 : 1; - } - // if one is *trusted* but the other isn't, that one comes first - // this overrides the primary attribute, even! - if ((trustedCerts.size() == 0) != (o.trustedCerts.size() == 0)) { - return trustedCerts.size() > o.trustedCerts.size() ? -1 : 1; - } - // if one key is primary but the other isn't, the primary one always comes first - if (isPrimary != o.isPrimary) { - return isPrimary ? -1 : 1; - } - return 0; - } - } - - /** - * Saves an UncachedKeyRing of the secret variant into the db. - * This method will fail if no corresponding public keyring is in the database! - */ - private int saveCanonicalizedSecretKeyRing(CanonicalizedSecretKeyRing keyRing) { - - long masterKeyId = keyRing.getMasterKeyId(); - log(LogType.MSG_IS, KeyFormattingUtils.convertKeyIdToHex(masterKeyId)); - mIndent += 1; - - try { - - // IF this is successful, it's a secret key - int result = SaveKeyringResult.SAVED_SECRET; - - // save secret keyring - try { - ContentValues values = new ContentValues(); - values.put(KeyRingData.MASTER_KEY_ID, masterKeyId); - values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded()); - // insert new version of this keyRing - Uri uri = KeyRingData.buildSecretKeyRingUri(masterKeyId); - if (mContentResolver.insert(uri, values) == null) { - log(LogType.MSG_IS_DB_EXCEPTION); - return SaveKeyringResult.RESULT_ERROR; - } - } catch (IOException e) { - Log.e(Constants.TAG, "Failed to encode key!", e); - log(LogType.MSG_IS_ERROR_IO_EXC); - return SaveKeyringResult.RESULT_ERROR; - } - - { - Uri uri = Keys.buildKeysUri(masterKeyId); - - // first, mark all keys as not available - ContentValues values = new ContentValues(); - values.put(Keys.HAS_SECRET, SecretKeyType.GNU_DUMMY.getNum()); - mContentResolver.update(uri, values, null, null); - - // then, mark exactly the keys we have available - log(LogType.MSG_IS_IMPORTING_SUBKEYS); - mIndent += 1; - for (CanonicalizedSecretKey sub : keyRing.secretKeyIterator()) { - long id = sub.getKeyId(); - SecretKeyType mode = sub.getSecretKeyTypeSuperExpensive(); - values.put(Keys.HAS_SECRET, mode.getNum()); - int upd = mContentResolver.update(uri, values, Keys.KEY_ID + " = ?", - new String[]{Long.toString(id)}); - if (upd == 1) { - switch (mode) { - case PASSPHRASE: - log(LogType.MSG_IS_SUBKEY_OK, - KeyFormattingUtils.convertKeyIdToHex(id) - ); - break; - case PASSPHRASE_EMPTY: - log(LogType.MSG_IS_SUBKEY_EMPTY, - KeyFormattingUtils.convertKeyIdToHex(id) - ); - break; - case PIN: - log(LogType.MSG_IS_SUBKEY_PIN, - KeyFormattingUtils.convertKeyIdToHex(id) - ); - break; - case GNU_DUMMY: - log(LogType.MSG_IS_SUBKEY_STRIPPED, - KeyFormattingUtils.convertKeyIdToHex(id) - ); - break; - case DIVERT_TO_CARD: - log(LogType.MSG_IS_SUBKEY_DIVERT, - KeyFormattingUtils.convertKeyIdToHex(id) - ); - break; - } - } else { - log(LogType.MSG_IS_SUBKEY_NONEXISTENT, - KeyFormattingUtils.convertKeyIdToHex(id) - ); - } - } - mIndent -= 1; - - // this implicitly leaves all keys which were not in the secret key ring - // with has_secret = 1 - } - - log(LogType.MSG_IS_SUCCESS); - return result; - - } finally { - mIndent -= 1; - } - - } - - /** - * Save a public keyring into the database. - *

- * This is a high level method, which takes care of merging all new information into the old and - * keep public and secret keyrings in sync. - *

- * If you want to merge keys in-memory only and not save in database set skipSave=true. - */ - public SaveKeyringResult savePublicKeyRing(UncachedKeyRing publicRing, Progressable progress, - String expectedFingerprint, - ArrayList canKeyRings, - boolean skipSave) { - - try { - long masterKeyId = publicRing.getMasterKeyId(); - log(LogType.MSG_IP, KeyFormattingUtils.convertKeyIdToHex(masterKeyId)); - mIndent += 1; - - if (publicRing.isSecret()) { - log(LogType.MSG_IP_BAD_TYPE_SECRET); - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - - CanonicalizedPublicKeyRing canPublicRing; - boolean alreadyExists = false; - - // If there is an old keyring, merge it - try { - UncachedKeyRing oldPublicRing = getCanonicalizedPublicKeyRing(masterKeyId).getUncachedKeyRing(); - alreadyExists = true; - - // Merge data from new public ring into the old one - log(LogType.MSG_IP_MERGE_PUBLIC); - publicRing = oldPublicRing.merge(publicRing, mLog, mIndent); - - // If this is null, there is an error in the log so we can just return - if (publicRing == null) { - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - - // Canonicalize this keyring, to assert a number of assumptions made about it. - canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent); - if (canPublicRing == null) { - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - if (canKeyRings != null) canKeyRings.add(canPublicRing); - - // Early breakout if nothing changed - if (Arrays.hashCode(publicRing.getEncoded()) - == Arrays.hashCode(oldPublicRing.getEncoded())) { - log(LogType.MSG_IP_SUCCESS_IDENTICAL); - return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog, null); - } - } catch (NotFoundException e) { - // Not an issue, just means we are dealing with a new keyring. - - // Canonicalize this keyring, to assert a number of assumptions made about it. - canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent); - if (canPublicRing == null) { - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - if (canKeyRings != null) canKeyRings.add(canPublicRing); - } - - // If there is a secret key, merge new data (if any) and save the key for later - CanonicalizedSecretKeyRing canSecretRing; - try { - UncachedKeyRing secretRing = getCanonicalizedSecretKeyRing(publicRing.getMasterKeyId()) - .getUncachedKeyRing(); - - // Merge data from new public ring into secret one - log(LogType.MSG_IP_MERGE_SECRET); - secretRing = secretRing.merge(publicRing, mLog, mIndent); - if (secretRing == null) { - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - // This has always been a secret key ring, this is a safe cast - canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent); - if (canSecretRing == null) { - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - - } catch (NotFoundException e) { - // No secret key available (this is what happens most of the time) - canSecretRing = null; - } - - - // If we have an expected fingerprint, make sure it matches - if (expectedFingerprint != null) { - if (!canPublicRing.containsBoundSubkey(expectedFingerprint)) { - log(LogType.MSG_IP_FINGERPRINT_ERROR); - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } else { - log(LogType.MSG_IP_FINGERPRINT_OK); - } - } - - int result; - if (skipSave) { - // skip save method, set fixed result - result = SaveKeyringResult.SAVED_PUBLIC - | (alreadyExists ? SaveKeyringResult.UPDATED : 0); - } else { - result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, canSecretRing != null); - } - - // Save the saved keyring (if any) - if (canSecretRing != null) { - progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100); - - int secretResult; - if (skipSave) { - // skip save method, set fixed result - secretResult = SaveKeyringResult.SAVED_SECRET; - } else { - secretResult = saveCanonicalizedSecretKeyRing(canSecretRing); - } - - if ((secretResult & SaveKeyringResult.RESULT_ERROR) != SaveKeyringResult.RESULT_ERROR) { - result |= SaveKeyringResult.SAVED_SECRET; - } - } - - return new SaveKeyringResult(result, mLog, canSecretRing); - } catch (IOException e) { - log(LogType.MSG_IP_ERROR_IO_EXC); - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } finally { - mIndent -= 1; - } - } - - public SaveKeyringResult savePublicKeyRing(UncachedKeyRing publicRing, Progressable progress, - String expectedFingerprint) { - return savePublicKeyRing(publicRing, progress, expectedFingerprint, null, false); - } - - public SaveKeyringResult savePublicKeyRing(UncachedKeyRing keyRing) { - return savePublicKeyRing(keyRing, new ProgressScaler(), null); - } - - public SaveKeyringResult saveSecretKeyRing(UncachedKeyRing secretRing, Progressable progress, - ArrayList canKeyRings, - boolean skipSave) { - - try { - long masterKeyId = secretRing.getMasterKeyId(); - log(LogType.MSG_IS, KeyFormattingUtils.convertKeyIdToHex(masterKeyId)); - mIndent += 1; - - if (!secretRing.isSecret()) { - log(LogType.MSG_IS_BAD_TYPE_PUBLIC); - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - - CanonicalizedSecretKeyRing canSecretRing; - boolean alreadyExists = false; - - // If there is an old secret key, merge it. - try { - UncachedKeyRing oldSecretRing = getCanonicalizedSecretKeyRing(masterKeyId).getUncachedKeyRing(); - alreadyExists = true; - - // Merge data from new secret ring into old one - log(LogType.MSG_IS_MERGE_SECRET); - secretRing = secretRing.merge(oldSecretRing, mLog, mIndent); - - // If this is null, there is an error in the log so we can just return - if (secretRing == null) { - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - - // Canonicalize this keyring, to assert a number of assumptions made about it. - // This is a safe cast, because we made sure this is a secret ring above - canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent); - if (canSecretRing == null) { - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - if (canKeyRings != null) canKeyRings.add(canSecretRing); - - // Early breakout if nothing changed - if (Arrays.hashCode(secretRing.getEncoded()) - == Arrays.hashCode(oldSecretRing.getEncoded())) { - log(LogType.MSG_IS_SUCCESS_IDENTICAL, - KeyFormattingUtils.convertKeyIdToHex(masterKeyId)); - return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog, null); - } - } catch (NotFoundException e) { - // Not an issue, just means we are dealing with a new keyring - - // Canonicalize this keyring, to assert a number of assumptions made about it. - // This is a safe cast, because we made sure this is a secret ring above - canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent); - if (canSecretRing == null) { - - // Special case: If keyring canonicalization failed, try again after adding - // all self-certificates from the public key. - try { - log(LogType.MSG_IS_MERGE_SPECIAL); - UncachedKeyRing oldPublicRing = getCanonicalizedPublicKeyRing(masterKeyId).getUncachedKeyRing(); - secretRing = secretRing.merge(oldPublicRing, mLog, mIndent); - canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent); - } catch (NotFoundException e2) { - // nothing, this is handled right in the next line - } - - if (canSecretRing == null) { - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - } - if (canKeyRings != null) canKeyRings.add(canSecretRing); - } - - // Merge new data into public keyring as well, if there is any - UncachedKeyRing publicRing; - try { - UncachedKeyRing oldPublicRing = getCanonicalizedPublicKeyRing(masterKeyId).getUncachedKeyRing(); - - // Merge data from new secret ring into public one - log(LogType.MSG_IS_MERGE_PUBLIC); - publicRing = oldPublicRing.merge(secretRing, mLog, mIndent); - if (publicRing == null) { - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - - } catch (NotFoundException e) { - log(LogType.MSG_IS_PUBRING_GENERATE); - publicRing = secretRing.extractPublicKeyRing(); - } - - CanonicalizedPublicKeyRing canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, - mIndent); - if (canPublicRing == null) { - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - - int publicResult; - if (skipSave) { - // skip save method, set fixed result - publicResult = SaveKeyringResult.SAVED_PUBLIC; - } else { - publicResult = saveCanonicalizedPublicKeyRing(canPublicRing, progress, true); - } - - if ((publicResult & SaveKeyringResult.RESULT_ERROR) == SaveKeyringResult.RESULT_ERROR) { - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } - - progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100); - - int result; - if (skipSave) { - // skip save method, set fixed result - result = SaveKeyringResult.SAVED_SECRET - | (alreadyExists ? SaveKeyringResult.UPDATED : 0); - } else { - result = saveCanonicalizedSecretKeyRing(canSecretRing); - } - - return new SaveKeyringResult(result, mLog, canSecretRing); - } catch (IOException e) { - log(LogType.MSG_IS_ERROR_IO_EXC); - return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); - } finally { - mIndent -= 1; - } - } - - public SaveKeyringResult saveSecretKeyRing(UncachedKeyRing secretRing, Progressable progress) { - return saveSecretKeyRing(secretRing, progress, null, false); - } - - @NonNull - public ConsolidateResult consolidateDatabaseStep1(Progressable progress) { - - OperationLog log = new OperationLog(); - int indent = 0; - - // 1a. fetch all secret keyrings into a cache file - log.add(LogType.MSG_CON, indent); - indent += 1; - - if (mConsolidateCritical) { - log.add(LogType.MSG_CON_RECURSIVE, indent); - return new ConsolidateResult(ConsolidateResult.RESULT_OK, log); - } - - progress.setProgress(R.string.progress_con_saving, 0, 100); - - // The consolidate operation can never be cancelled! - progress.setPreventCancel(); - - try { - - log.add(LogType.MSG_CON_SAVE_SECRET, indent); - indent += 1; - - final Cursor cursor = mContentResolver.query(KeyRingData.buildSecretKeyRingUri(), - new String[]{KeyRingData.KEY_RING_DATA}, null, null, null); - - if (cursor == null) { - log.add(LogType.MSG_CON_ERROR_DB, indent); - return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); - } - - // No keys existing might be a legitimate option, we write an empty file in that case - cursor.moveToFirst(); - ParcelableFileCache cache = - new ParcelableFileCache<>(mContext, "consolidate_secret.pcl"); - cache.writeCache(cursor.getCount(), new Iterator() { - ParcelableKeyRing ring; - - @Override - public boolean hasNext() { - if (ring != null) { - return true; - } - if (cursor.isAfterLast()) { - return false; - } - ring = new ParcelableKeyRing(cursor.getBlob(0)); - cursor.moveToNext(); - return true; - } - - @Override - public ParcelableKeyRing next() { - try { - return ring; - } finally { - ring = null; - } - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - }); - cursor.close(); - - } catch (IOException e) { - Log.e(Constants.TAG, "error saving secret", e); - log.add(LogType.MSG_CON_ERROR_IO_SECRET, indent); - return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); - } finally { - indent -= 1; - } - - progress.setProgress(R.string.progress_con_saving, 3, 100); - - // 1b. fetch all public keyrings into a cache file - try { - - log.add(LogType.MSG_CON_SAVE_PUBLIC, indent); - indent += 1; - - final Cursor cursor = mContentResolver.query( - KeyRingData.buildPublicKeyRingUri(), - new String[]{KeyRingData.KEY_RING_DATA}, null, null, null); - - if (cursor == null) { - log.add(LogType.MSG_CON_ERROR_DB, indent); - return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); - } - - // No keys existing might be a legitimate option, we write an empty file in that case - cursor.moveToFirst(); - ParcelableFileCache cache = - new ParcelableFileCache<>(mContext, "consolidate_public.pcl"); - cache.writeCache(cursor.getCount(), new Iterator() { - ParcelableKeyRing ring; - - @Override - public boolean hasNext() { - if (ring != null) { - return true; - } - if (cursor.isAfterLast()) { - return false; - } - ring = new ParcelableKeyRing(cursor.getBlob(0)); - cursor.moveToNext(); - return true; - } - - @Override - public ParcelableKeyRing next() { - try { - return ring; - } finally { - ring = null; - } - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - }); - cursor.close(); - - } catch (IOException e) { - Log.e(Constants.TAG, "error saving public", e); - log.add(LogType.MSG_CON_ERROR_IO_PUBLIC, indent); - return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); - } finally { - indent -= 1; - } - - log.add(LogType.MSG_CON_CRITICAL_IN, indent); - Preferences.getPreferences(mContext).setCachedConsolidate(true); - - return consolidateDatabaseStep2(log, indent, progress, false); - } - - @NonNull - public ConsolidateResult consolidateDatabaseStep2(Progressable progress) { - return consolidateDatabaseStep2(new OperationLog(), 0, progress, true); - } - - private static boolean mConsolidateCritical = false; - - @NonNull - private ConsolidateResult consolidateDatabaseStep2( - OperationLog log, int indent, Progressable progress, boolean recovery) { - - synchronized (DatabaseInteractor.class) { - if (mConsolidateCritical) { - log.add(LogType.MSG_CON_ERROR_CONCURRENT, indent); - return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); - } - mConsolidateCritical = true; - } - - try { - Preferences prefs = Preferences.getPreferences(mContext); - - if (recovery) { - log.add(LogType.MSG_CON_RECOVER, indent); - indent += 1; - } - - if (!prefs.getCachedConsolidate()) { - log.add(LogType.MSG_CON_ERROR_BAD_STATE, indent); - return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); - } - - // 2. wipe database (IT'S DANGEROUS) - - // first, backup our list of updated key times - ArrayList updatedKeysValues = new ArrayList<>(); - final int INDEX_MASTER_KEY_ID = 0; - final int INDEX_LAST_UPDATED = 1; - Cursor lastUpdatedCursor = mContentResolver.query( - UpdatedKeys.CONTENT_URI, - new String[]{ - UpdatedKeys.MASTER_KEY_ID, - UpdatedKeys.LAST_UPDATED - }, - null, null, null); - while (lastUpdatedCursor.moveToNext()) { - ContentValues values = new ContentValues(); - values.put(UpdatedKeys.MASTER_KEY_ID, - lastUpdatedCursor.getLong(INDEX_MASTER_KEY_ID)); - values.put(UpdatedKeys.LAST_UPDATED, - lastUpdatedCursor.getLong(INDEX_LAST_UPDATED)); - updatedKeysValues.add(values); - } - lastUpdatedCursor.close(); - - log.add(LogType.MSG_CON_DB_CLEAR, indent); - mContentResolver.delete(KeyRings.buildUnifiedKeyRingsUri(), null, null); - - ParcelableFileCache cacheSecret, cachePublic; - - // Set flag that we have a cached consolidation here - try { - cacheSecret = new ParcelableFileCache<>(mContext, "consolidate_secret.pcl"); - IteratorWithSize itSecrets = cacheSecret.readCache(false); - int numSecrets = itSecrets.getSize(); - - log.add(LogType.MSG_CON_REIMPORT_SECRET, indent, numSecrets); - indent += 1; - - // 3. Re-Import secret keyrings from cache - if (numSecrets > 0) { - - ImportKeyResult result = new ImportOperation(mContext, this, - new ProgressFixedScaler(progress, 10, 25, 100, R.string.progress_con_reimport)) - .serialKeyRingImport(itSecrets, numSecrets, null, null, false); - log.add(result, indent); - } else { - log.add(LogType.MSG_CON_REIMPORT_SECRET_SKIP, indent); - } - - } catch (IOException e) { - Log.e(Constants.TAG, "error importing secret", e); - log.add(LogType.MSG_CON_ERROR_SECRET, indent); - return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); - } finally { - indent -= 1; - } - - try { - - cachePublic = new ParcelableFileCache<>(mContext, "consolidate_public.pcl"); - IteratorWithSize itPublics = cachePublic.readCache(); - int numPublics = itPublics.getSize(); - - log.add(LogType.MSG_CON_REIMPORT_PUBLIC, indent, numPublics); - indent += 1; - - // 4. Re-Import public keyrings from cache - if (numPublics > 0) { - - ImportKeyResult result = new ImportOperation(mContext, this, - new ProgressFixedScaler(progress, 25, 99, 100, R.string.progress_con_reimport)) - .serialKeyRingImport(itPublics, numPublics, null, null, false); - log.add(result, indent); - // re-insert our backed up list of updated key times - // TODO: can this cause issues in case a public key re-import failed? - mContentResolver.bulkInsert(UpdatedKeys.CONTENT_URI, - updatedKeysValues.toArray(new ContentValues[updatedKeysValues.size()])); - } else { - log.add(LogType.MSG_CON_REIMPORT_PUBLIC_SKIP, indent); - } - - } catch (IOException e) { - Log.e(Constants.TAG, "error importing public", e); - log.add(LogType.MSG_CON_ERROR_PUBLIC, indent); - return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); - } finally { - indent -= 1; - } - - log.add(LogType.MSG_CON_CRITICAL_OUT, indent); - Preferences.getPreferences(mContext).setCachedConsolidate(false); - - // 5. Delete caches - try { - log.add(LogType.MSG_CON_DELETE_SECRET, indent); - indent += 1; - cacheSecret.delete(); - } catch (IOException e) { - // doesn't /really/ matter - Log.e(Constants.TAG, "IOException during delete of secret cache", e); - log.add(LogType.MSG_CON_WARN_DELETE_SECRET, indent); - } finally { - indent -= 1; - } - - try { - log.add(LogType.MSG_CON_DELETE_PUBLIC, indent); - indent += 1; - cachePublic.delete(); - } catch (IOException e) { - // doesn't /really/ matter - Log.e(Constants.TAG, "IOException during deletion of public cache", e); - log.add(LogType.MSG_CON_WARN_DELETE_PUBLIC, indent); - } finally { - indent -= 1; - } - - progress.setProgress(100, 100); - log.add(LogType.MSG_CON_SUCCESS, indent); - - return new ConsolidateResult(ConsolidateResult.RESULT_OK, log); - - } finally { - mConsolidateCritical = false; - } - - } - - /** - * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing - */ - private ContentProviderOperation - buildCertOperations(long masterKeyId, int rank, WrappedSignature cert, int verified) - throws IOException { - ContentValues values = new ContentValues(); - values.put(Certs.MASTER_KEY_ID, masterKeyId); - values.put(Certs.RANK, rank); - values.put(Certs.KEY_ID_CERTIFIER, cert.getKeyId()); - values.put(Certs.TYPE, cert.getSignatureType()); - values.put(Certs.CREATION, cert.getCreationTime().getTime() / 1000); - values.put(Certs.VERIFIED, verified); - values.put(Certs.DATA, cert.getEncoded()); - - Uri uri = Certs.buildCertsUri(masterKeyId); - - return ContentProviderOperation.newInsert(uri).withValues(values).build(); - } - - /** - * Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing - */ - private ContentProviderOperation - buildUserIdOperations(long masterKeyId, UserPacketItem item, int rank) { - ContentValues values = new ContentValues(); - values.put(UserPackets.MASTER_KEY_ID, masterKeyId); - values.put(UserPackets.TYPE, item.type); - values.put(UserPackets.USER_ID, item.userId); - values.put(UserPackets.NAME, item.name); - values.put(UserPackets.EMAIL, item.email); - values.put(UserPackets.COMMENT, item.comment); - values.put(UserPackets.ATTRIBUTE_DATA, item.attributeData); - values.put(UserPackets.IS_PRIMARY, item.isPrimary); - values.put(UserPackets.IS_REVOKED, item.selfRevocation != null); - values.put(UserPackets.RANK, rank); - - Uri uri = UserPackets.buildUserIdsUri(masterKeyId); - - return ContentProviderOperation.newInsert(uri).withValues(values).build(); - } - private String getKeyRingAsArmoredString(byte[] data) throws IOException, PgpGeneralException { UncachedKeyRing keyRing = UncachedKeyRing.decodeFromData(data); @@ -1540,19 +230,20 @@ public class DatabaseInteractor { public String getKeyRingAsArmoredString(Uri uri) throws NotFoundException, IOException, PgpGeneralException { byte[] data = (byte[]) getGenericData( - uri, KeyRingData.KEY_RING_DATA, DatabaseInteractor.FIELD_TYPE_BLOB); + uri, KeyRingData.KEY_RING_DATA, FIELD_TYPE_BLOB); return getKeyRingAsArmoredString(data); } - public Uri renewKeyLastUpdatedTime(long masterKeyId, long time, TimeUnit timeUnit) { - ContentValues values = new ContentValues(); - values.put(UpdatedKeys.MASTER_KEY_ID, masterKeyId); - values.put(UpdatedKeys.LAST_UPDATED, timeUnit.toSeconds(time)); - - return mContentResolver.insert(UpdatedKeys.CONTENT_URI, values); - } - public ContentResolver getContentResolver() { return mContentResolver; } + + public static class NotFoundException extends Exception { + public NotFoundException() { + } + + public NotFoundException(String name) { + super(name); + } + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/DatabaseReadWriteInteractor.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/DatabaseReadWriteInteractor.java new file mode 100644 index 000000000..d9b0a1f3f --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/DatabaseReadWriteInteractor.java @@ -0,0 +1,1345 @@ +/* + * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2014 Vincent Breitmoser + * + * 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.provider; + + +import android.content.ContentProviderOperation; +import android.content.ContentValues; +import android.content.Context; +import android.content.OperationApplicationException; +import android.database.Cursor; +import android.net.Uri; +import android.os.RemoteException; +import android.support.annotation.NonNull; +import android.support.v4.util.LongSparseArray; + +import org.openintents.openpgp.util.OpenPgpUtils; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.ImportOperation; +import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; +import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; +import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey; +import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; +import org.sufficientlysecure.keychain.pgp.WrappedSignature; +import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; +import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.IterableIterator; +import org.sufficientlysecure.keychain.util.IteratorWithSize; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ParcelableFileCache; +import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.ProgressFixedScaler; +import org.sufficientlysecure.keychain.util.ProgressScaler; +import org.sufficientlysecure.keychain.util.Utf8Util; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * This class contains high level methods for database access. Despite its + * name, it is not only a helper but actually the main interface for all + * synchronous database operations. + *

+ * Operations in this class write logs. These can be obtained from the + * OperationResultParcel return values directly, but are also accumulated over + * the lifetime of the executing ProviderHelper object unless the resetLog() + * method is called to start a new one specifically. + */ +public class DatabaseReadWriteInteractor extends DatabaseInteractor { + private final Context mContext; + + public DatabaseReadWriteInteractor(Context context) { + this(context, new OperationLog(), 0); + } + + public DatabaseReadWriteInteractor(Context context, OperationLog log) { + this(context, log, 0); + } + + public DatabaseReadWriteInteractor(Context context, OperationLog log, int indent) { + super(context.getContentResolver(), log, indent); + + mContext = context; + } + + private LongSparseArray getTrustedMasterKeys() { + Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{ + KeyRings.MASTER_KEY_ID, + // we pick from cache only information that is not easily available from keyrings + KeyRings.HAS_ANY_SECRET, KeyRings.VERIFIED, + // and of course, ring data + KeyRings.PUBKEY_DATA + }, KeyRings.HAS_ANY_SECRET + " = 1", null, null); + + try { + LongSparseArray result = new LongSparseArray<>(); + + if (cursor != null && cursor.moveToFirst()) do { + long masterKeyId = cursor.getLong(0); + int verified = cursor.getInt(2); + byte[] blob = cursor.getBlob(3); + if (blob != null) { + result.put(masterKeyId, + new CanonicalizedPublicKeyRing(blob, verified).getPublicKey()); + } + } while (cursor.moveToNext()); + + return result; + + } finally { + if (cursor != null) { + cursor.close(); + } + } + + } + + // bits, in order: CESA. make SURE these are correct, we will get bad log entries otherwise!! + private static final LogType LOG_TYPES_FLAG_MASTER[] = new LogType[]{ + LogType.MSG_IP_MASTER_FLAGS_XXXX, LogType.MSG_IP_MASTER_FLAGS_CXXX, + LogType.MSG_IP_MASTER_FLAGS_XEXX, LogType.MSG_IP_MASTER_FLAGS_CEXX, + LogType.MSG_IP_MASTER_FLAGS_XXSX, LogType.MSG_IP_MASTER_FLAGS_CXSX, + LogType.MSG_IP_MASTER_FLAGS_XESX, LogType.MSG_IP_MASTER_FLAGS_CESX, + LogType.MSG_IP_MASTER_FLAGS_XXXA, LogType.MSG_IP_MASTER_FLAGS_CXXA, + LogType.MSG_IP_MASTER_FLAGS_XEXA, LogType.MSG_IP_MASTER_FLAGS_CEXA, + LogType.MSG_IP_MASTER_FLAGS_XXSA, LogType.MSG_IP_MASTER_FLAGS_CXSA, + LogType.MSG_IP_MASTER_FLAGS_XESA, LogType.MSG_IP_MASTER_FLAGS_CESA + }; + + // same as above, but for subkeys + private static final LogType LOG_TYPES_FLAG_SUBKEY[] = new LogType[]{ + LogType.MSG_IP_SUBKEY_FLAGS_XXXX, LogType.MSG_IP_SUBKEY_FLAGS_CXXX, + LogType.MSG_IP_SUBKEY_FLAGS_XEXX, LogType.MSG_IP_SUBKEY_FLAGS_CEXX, + LogType.MSG_IP_SUBKEY_FLAGS_XXSX, LogType.MSG_IP_SUBKEY_FLAGS_CXSX, + LogType.MSG_IP_SUBKEY_FLAGS_XESX, LogType.MSG_IP_SUBKEY_FLAGS_CESX, + LogType.MSG_IP_SUBKEY_FLAGS_XXXA, LogType.MSG_IP_SUBKEY_FLAGS_CXXA, + LogType.MSG_IP_SUBKEY_FLAGS_XEXA, LogType.MSG_IP_SUBKEY_FLAGS_CEXA, + LogType.MSG_IP_SUBKEY_FLAGS_XXSA, LogType.MSG_IP_SUBKEY_FLAGS_CXSA, + LogType.MSG_IP_SUBKEY_FLAGS_XESA, LogType.MSG_IP_SUBKEY_FLAGS_CESA + }; + + /** + * Saves an UncachedKeyRing of the public variant into the db. + *

+ * This method will not delete all previous data for this masterKeyId from the database prior + * to inserting. All public data is effectively re-inserted, secret keyrings are left deleted + * and need to be saved externally to be preserved past the operation. + */ + @SuppressWarnings("unchecked") + private int saveCanonicalizedPublicKeyRing(CanonicalizedPublicKeyRing keyRing, + Progressable progress, boolean selfCertsAreTrusted) { + + // start with ok result + int result = SaveKeyringResult.SAVED_PUBLIC; + + long masterKeyId = keyRing.getMasterKeyId(); + UncachedPublicKey masterKey = keyRing.getPublicKey(); + + ArrayList operations; + try { + + log(LogType.MSG_IP_PREPARE); + mIndent += 1; + + // save all keys and userIds included in keyRing object in database + operations = new ArrayList<>(); + + log(LogType.MSG_IP_INSERT_KEYRING); + { // insert keyring + ContentValues values = new ContentValues(); + values.put(KeyRingData.MASTER_KEY_ID, masterKeyId); + try { + values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded()); + } catch (IOException e) { + log(LogType.MSG_IP_ENCODE_FAIL); + return SaveKeyringResult.RESULT_ERROR; + } + + Uri uri = KeyRingData.buildPublicKeyRingUri(masterKeyId); + operations.add(ContentProviderOperation.newInsert(uri).withValues(values).build()); + } + + log(LogType.MSG_IP_INSERT_SUBKEYS); + progress.setProgress(LogType.MSG_IP_INSERT_SUBKEYS.getMsgId(), 40, 100); + mIndent += 1; + { // insert subkeys + Uri uri = Keys.buildKeysUri(masterKeyId); + int rank = 0; + for (CanonicalizedPublicKey key : keyRing.publicKeyIterator()) { + long keyId = key.getKeyId(); + log(keyId == masterKeyId ? LogType.MSG_IP_MASTER : LogType.MSG_IP_SUBKEY, + KeyFormattingUtils.convertKeyIdToHex(keyId) + ); + mIndent += 1; + + ContentValues values = new ContentValues(); + values.put(Keys.MASTER_KEY_ID, masterKeyId); + values.put(Keys.RANK, rank); + + values.put(Keys.KEY_ID, key.getKeyId()); + values.put(Keys.KEY_SIZE, key.getBitStrength()); + values.put(Keys.KEY_CURVE_OID, key.getCurveOid()); + values.put(Keys.ALGORITHM, key.getAlgorithm()); + values.put(Keys.FINGERPRINT, key.getFingerprint()); + + boolean c = key.canCertify(), e = key.canEncrypt(), s = key.canSign(), a = key.canAuthenticate(); + values.put(Keys.CAN_CERTIFY, c); + values.put(Keys.CAN_ENCRYPT, e); + values.put(Keys.CAN_SIGN, s); + values.put(Keys.CAN_AUTHENTICATE, a); + values.put(Keys.IS_REVOKED, key.isRevoked()); + values.put(Keys.IS_SECURE, key.isSecure()); + + // see above + if (masterKeyId == keyId) { + if (key.getKeyUsage() == null) { + log(LogType.MSG_IP_MASTER_FLAGS_UNSPECIFIED); + } else { + log(LOG_TYPES_FLAG_MASTER[(c ? 1 : 0) + (e ? 2 : 0) + (s ? 4 : 0) + (a ? 8 : 0)]); + } + } else { + if (key.getKeyUsage() == null) { + log(LogType.MSG_IP_SUBKEY_FLAGS_UNSPECIFIED); + } else { + log(LOG_TYPES_FLAG_SUBKEY[(c ? 1 : 0) + (e ? 2 : 0) + (s ? 4 : 0) + (a ? 8 : 0)]); + } + } + + Date creation = key.getCreationTime(); + values.put(Keys.CREATION, creation.getTime() / 1000); + Date expiryDate = key.getExpiryTime(); + if (expiryDate != null) { + values.put(Keys.EXPIRY, expiryDate.getTime() / 1000); + if (key.isExpired()) { + log(keyId == masterKeyId ? + LogType.MSG_IP_MASTER_EXPIRED : LogType.MSG_IP_SUBKEY_EXPIRED, + expiryDate.toString()); + } else { + log(keyId == masterKeyId ? + LogType.MSG_IP_MASTER_EXPIRES : LogType.MSG_IP_SUBKEY_EXPIRES, + expiryDate.toString()); + } + } + + operations.add(ContentProviderOperation.newInsert(uri).withValues(values).build()); + ++rank; + mIndent -= 1; + } + } + mIndent -= 1; + + // get a list of owned secret keys, for verification filtering + LongSparseArray trustedKeys = getTrustedMasterKeys(); + + // classify and order user ids. primary are moved to the front, revoked to the back, + // otherwise the order in the keyfile is preserved. + List uids = new ArrayList<>(); + + if (trustedKeys.size() == 0) { + log(LogType.MSG_IP_UID_CLASSIFYING_ZERO); + } else { + log(LogType.MSG_IP_UID_CLASSIFYING, trustedKeys.size()); + } + mIndent += 1; + for (byte[] rawUserId : masterKey.getUnorderedRawUserIds()) { + String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId); + UserPacketItem item = new UserPacketItem(); + uids.add(item); + OpenPgpUtils.UserId splitUserId = KeyRing.splitUserId(userId); + item.userId = userId; + item.name = splitUserId.name; + item.email = splitUserId.email; + item.comment = splitUserId.comment; + int unknownCerts = 0; + + log(LogType.MSG_IP_UID_PROCESSING, userId); + mIndent += 1; + // look through signatures for this specific key + for (WrappedSignature cert : new IterableIterator<>( + masterKey.getSignaturesForRawId(rawUserId))) { + long certId = cert.getKeyId(); + // self signature + if (certId == masterKeyId) { + + // NOTE self-certificates are already verified during canonicalization, + // AND we know there is at most one cert plus at most one revocation + if (!cert.isRevocation()) { + item.selfCert = cert; + item.isPrimary = cert.isPrimaryUserId(); + } else { + item.selfRevocation = cert; + log(LogType.MSG_IP_UID_REVOKED); + } + continue; + + } + + // do we have a trusted key for this? + if (trustedKeys.indexOfKey(certId) < 0) { + unknownCerts += 1; + continue; + } + + // verify signatures from known private keys + CanonicalizedPublicKey trustedKey = trustedKeys.get(certId); + + try { + cert.init(trustedKey); + // if it doesn't certify, leave a note and skip + if (!cert.verifySignature(masterKey, rawUserId)) { + log(LogType.MSG_IP_UID_CERT_BAD); + continue; + } + + log(cert.isRevocation() + ? LogType.MSG_IP_UID_CERT_GOOD_REVOKE + : LogType.MSG_IP_UID_CERT_GOOD, + KeyFormattingUtils.convertKeyIdToHexShort(trustedKey.getKeyId()) + ); + + // check if there is a previous certificate + WrappedSignature prev = item.trustedCerts.get(cert.getKeyId()); + if (prev != null) { + // if it's newer, skip this one + if (prev.getCreationTime().after(cert.getCreationTime())) { + log(LogType.MSG_IP_UID_CERT_OLD); + continue; + } + // if the previous one was a non-revokable certification, no need to look further + if (!prev.isRevocation() && !prev.isRevokable()) { + log(LogType.MSG_IP_UID_CERT_NONREVOKE); + continue; + } + log(LogType.MSG_IP_UID_CERT_NEW); + } + item.trustedCerts.put(cert.getKeyId(), cert); + + } catch (PgpGeneralException e) { + log(LogType.MSG_IP_UID_CERT_ERROR, + KeyFormattingUtils.convertKeyIdToHex(cert.getKeyId())); + } + + } + + if (unknownCerts > 0) { + log(LogType.MSG_IP_UID_CERTS_UNKNOWN, unknownCerts); + } + mIndent -= 1; + + } + mIndent -= 1; + + ArrayList userAttributes = masterKey.getUnorderedUserAttributes(); + // Don't spam the log if there aren't even any attributes + if (!userAttributes.isEmpty()) { + log(LogType.MSG_IP_UAT_CLASSIFYING); + } + + mIndent += 1; + for (WrappedUserAttribute userAttribute : userAttributes) { + + UserPacketItem item = new UserPacketItem(); + uids.add(item); + item.type = userAttribute.getType(); + item.attributeData = userAttribute.getEncoded(); + + int unknownCerts = 0; + + switch (item.type) { + case WrappedUserAttribute.UAT_IMAGE: + log(LogType.MSG_IP_UAT_PROCESSING_IMAGE); + break; + default: + log(LogType.MSG_IP_UAT_PROCESSING_UNKNOWN); + break; + } + mIndent += 1; + // look through signatures for this specific key + for (WrappedSignature cert : new IterableIterator<>( + masterKey.getSignaturesForUserAttribute(userAttribute))) { + long certId = cert.getKeyId(); + // self signature + if (certId == masterKeyId) { + + // NOTE self-certificates are already verified during canonicalization, + // AND we know there is at most one cert plus at most one revocation + // AND the revocation only exists if there is no newer certification + if (!cert.isRevocation()) { + item.selfCert = cert; + } else { + item.selfRevocation = cert; + log(LogType.MSG_IP_UAT_REVOKED); + } + continue; + + } + + // do we have a trusted key for this? + if (trustedKeys.indexOfKey(certId) < 0) { + unknownCerts += 1; + continue; + } + + // verify signatures from known private keys + CanonicalizedPublicKey trustedKey = trustedKeys.get(certId); + + try { + cert.init(trustedKey); + // if it doesn't certify, leave a note and skip + if (!cert.verifySignature(masterKey, userAttribute)) { + log(LogType.MSG_IP_UAT_CERT_BAD); + continue; + } + + log(cert.isRevocation() + ? LogType.MSG_IP_UAT_CERT_GOOD_REVOKE + : LogType.MSG_IP_UAT_CERT_GOOD, + KeyFormattingUtils.convertKeyIdToHexShort(trustedKey.getKeyId()) + ); + + // check if there is a previous certificate + WrappedSignature prev = item.trustedCerts.get(cert.getKeyId()); + if (prev != null) { + // if it's newer, skip this one + if (prev.getCreationTime().after(cert.getCreationTime())) { + log(LogType.MSG_IP_UAT_CERT_OLD); + continue; + } + // if the previous one was a non-revokable certification, no need to look further + if (!prev.isRevocation() && !prev.isRevokable()) { + log(LogType.MSG_IP_UAT_CERT_NONREVOKE); + continue; + } + log(LogType.MSG_IP_UAT_CERT_NEW); + } + item.trustedCerts.put(cert.getKeyId(), cert); + + } catch (PgpGeneralException e) { + log(LogType.MSG_IP_UAT_CERT_ERROR, + KeyFormattingUtils.convertKeyIdToHex(cert.getKeyId())); + } + + } + + if (unknownCerts > 0) { + log(LogType.MSG_IP_UAT_CERTS_UNKNOWN, unknownCerts); + } + mIndent -= 1; + + } + mIndent -= 1; + + progress.setProgress(LogType.MSG_IP_UID_REORDER.getMsgId(), 65, 100); + log(LogType.MSG_IP_UID_REORDER); + // primary before regular before revoked (see UserIdItem.compareTo) + // this is a stable sort, so the order of keys is otherwise preserved. + Collections.sort(uids); + // iterate and put into db + for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) { + UserPacketItem item = uids.get(userIdRank); + operations.add(buildUserIdOperations(masterKeyId, item, userIdRank)); + + if (item.selfRevocation != null) { + operations.add(buildCertOperations(masterKeyId, userIdRank, item.selfRevocation, + Certs.VERIFIED_SELF)); + // don't bother with trusted certs if the uid is revoked, anyways + continue; + } + + if (item.selfCert == null) { + throw new AssertionError("User ids MUST be self-certified at this point!!"); + } + + operations.add(buildCertOperations(masterKeyId, userIdRank, item.selfCert, + selfCertsAreTrusted ? Certs.VERIFIED_SECRET : Certs.VERIFIED_SELF)); + + // iterate over signatures + for (int i = 0; i < item.trustedCerts.size(); i++) { + WrappedSignature sig = item.trustedCerts.valueAt(i); + // if it's a revocation + if (sig.isRevocation()) { + // don't further process it + continue; + } + // otherwise, build database operation + operations.add(buildCertOperations( + masterKeyId, userIdRank, sig, Certs.VERIFIED_SECRET)); + } + } + + } catch (IOException e) { + log(LogType.MSG_IP_ERROR_IO_EXC); + Log.e(Constants.TAG, "IOException during import", e); + return SaveKeyringResult.RESULT_ERROR; + } finally { + mIndent -= 1; + } + + // before deleting key, retrieve it's last updated time + final int INDEX_MASTER_KEY_ID = 0; + final int INDEX_LAST_UPDATED = 1; + Cursor lastUpdatedCursor = mContentResolver.query( + UpdatedKeys.CONTENT_URI, + new String[]{ + UpdatedKeys.MASTER_KEY_ID, + UpdatedKeys.LAST_UPDATED + }, + UpdatedKeys.MASTER_KEY_ID + " = ?", + new String[]{"" + masterKeyId}, + null + ); + if (lastUpdatedCursor.moveToNext()) { + // there was an entry to re-insert + // this operation must happen after the new key is inserted + ContentValues lastUpdatedEntry = new ContentValues(2); + lastUpdatedEntry.put(UpdatedKeys.MASTER_KEY_ID, + lastUpdatedCursor.getLong(INDEX_MASTER_KEY_ID)); + lastUpdatedEntry.put(UpdatedKeys.LAST_UPDATED, + lastUpdatedCursor.getLong(INDEX_LAST_UPDATED)); + operations.add( + ContentProviderOperation + .newInsert(UpdatedKeys.CONTENT_URI) + .withValues(lastUpdatedEntry) + .build() + ); + } + lastUpdatedCursor.close(); + + try { + // delete old version of this keyRing, which also deletes all keys and userIds on cascade + int deleted = mContentResolver.delete( + KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null); + if (deleted > 0) { + log(LogType.MSG_IP_DELETE_OLD_OK); + result |= SaveKeyringResult.UPDATED; + } else { + log(LogType.MSG_IP_DELETE_OLD_FAIL); + } + + log(LogType.MSG_IP_APPLY_BATCH); + progress.setProgress(LogType.MSG_IP_APPLY_BATCH.getMsgId(), 75, 100); + mContentResolver.applyBatch(KeychainContract.CONTENT_AUTHORITY, operations); + + log(LogType.MSG_IP_SUCCESS); + progress.setProgress(LogType.MSG_IP_SUCCESS.getMsgId(), 90, 100); + return result; + + } catch (RemoteException e) { + log(LogType.MSG_IP_ERROR_REMOTE_EX); + Log.e(Constants.TAG, "RemoteException during import", e); + return SaveKeyringResult.RESULT_ERROR; + } catch (OperationApplicationException e) { + log(LogType.MSG_IP_ERROR_OP_EXC); + Log.e(Constants.TAG, "OperationApplicationException during import", e); + return SaveKeyringResult.RESULT_ERROR; + } + + } + + private static class UserPacketItem implements Comparable { + Integer type; + String userId; + String name; + String email; + String comment; + byte[] attributeData; + boolean isPrimary = false; + WrappedSignature selfCert; + WrappedSignature selfRevocation; + LongSparseArray trustedCerts = new LongSparseArray<>(); + + @Override + public int compareTo(@NonNull UserPacketItem o) { + // revoked keys always come last! + //noinspection DoubleNegation + if ((selfRevocation != null) != (o.selfRevocation != null)) { + return selfRevocation != null ? 1 : -1; + } + // if one is a user id, but the other isn't, the user id always comes first. + // we compare for null values here, so != is the correct operator! + // noinspection NumberEquality + if (type != o.type) { + return type == null ? -1 : 1; + } + // if one is *trusted* but the other isn't, that one comes first + // this overrides the primary attribute, even! + if ((trustedCerts.size() == 0) != (o.trustedCerts.size() == 0)) { + return trustedCerts.size() > o.trustedCerts.size() ? -1 : 1; + } + // if one key is primary but the other isn't, the primary one always comes first + if (isPrimary != o.isPrimary) { + return isPrimary ? -1 : 1; + } + return 0; + } + } + + /** + * Saves an UncachedKeyRing of the secret variant into the db. + * This method will fail if no corresponding public keyring is in the database! + */ + private int saveCanonicalizedSecretKeyRing(CanonicalizedSecretKeyRing keyRing) { + + long masterKeyId = keyRing.getMasterKeyId(); + log(LogType.MSG_IS, KeyFormattingUtils.convertKeyIdToHex(masterKeyId)); + mIndent += 1; + + try { + + // IF this is successful, it's a secret key + int result = SaveKeyringResult.SAVED_SECRET; + + // save secret keyring + try { + ContentValues values = new ContentValues(); + values.put(KeyRingData.MASTER_KEY_ID, masterKeyId); + values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded()); + // insert new version of this keyRing + Uri uri = KeyRingData.buildSecretKeyRingUri(masterKeyId); + if (mContentResolver.insert(uri, values) == null) { + log(LogType.MSG_IS_DB_EXCEPTION); + return SaveKeyringResult.RESULT_ERROR; + } + } catch (IOException e) { + Log.e(Constants.TAG, "Failed to encode key!", e); + log(LogType.MSG_IS_ERROR_IO_EXC); + return SaveKeyringResult.RESULT_ERROR; + } + + { + Uri uri = Keys.buildKeysUri(masterKeyId); + + // first, mark all keys as not available + ContentValues values = new ContentValues(); + values.put(Keys.HAS_SECRET, SecretKeyType.GNU_DUMMY.getNum()); + mContentResolver.update(uri, values, null, null); + + // then, mark exactly the keys we have available + log(LogType.MSG_IS_IMPORTING_SUBKEYS); + mIndent += 1; + for (CanonicalizedSecretKey sub : keyRing.secretKeyIterator()) { + long id = sub.getKeyId(); + SecretKeyType mode = sub.getSecretKeyTypeSuperExpensive(); + values.put(Keys.HAS_SECRET, mode.getNum()); + int upd = mContentResolver.update(uri, values, Keys.KEY_ID + " = ?", + new String[]{Long.toString(id)}); + if (upd == 1) { + switch (mode) { + case PASSPHRASE: + log(LogType.MSG_IS_SUBKEY_OK, + KeyFormattingUtils.convertKeyIdToHex(id) + ); + break; + case PASSPHRASE_EMPTY: + log(LogType.MSG_IS_SUBKEY_EMPTY, + KeyFormattingUtils.convertKeyIdToHex(id) + ); + break; + case PIN: + log(LogType.MSG_IS_SUBKEY_PIN, + KeyFormattingUtils.convertKeyIdToHex(id) + ); + break; + case GNU_DUMMY: + log(LogType.MSG_IS_SUBKEY_STRIPPED, + KeyFormattingUtils.convertKeyIdToHex(id) + ); + break; + case DIVERT_TO_CARD: + log(LogType.MSG_IS_SUBKEY_DIVERT, + KeyFormattingUtils.convertKeyIdToHex(id) + ); + break; + } + } else { + log(LogType.MSG_IS_SUBKEY_NONEXISTENT, + KeyFormattingUtils.convertKeyIdToHex(id) + ); + } + } + mIndent -= 1; + + // this implicitly leaves all keys which were not in the secret key ring + // with has_secret = 1 + } + + log(LogType.MSG_IS_SUCCESS); + return result; + + } finally { + mIndent -= 1; + } + + } + + /** + * Save a public keyring into the database. + *

+ * This is a high level method, which takes care of merging all new information into the old and + * keep public and secret keyrings in sync. + *

+ * If you want to merge keys in-memory only and not save in database set skipSave=true. + */ + public SaveKeyringResult savePublicKeyRing(UncachedKeyRing publicRing, Progressable progress, + String expectedFingerprint, + ArrayList canKeyRings, + boolean skipSave) { + + try { + long masterKeyId = publicRing.getMasterKeyId(); + log(LogType.MSG_IP, KeyFormattingUtils.convertKeyIdToHex(masterKeyId)); + mIndent += 1; + + if (publicRing.isSecret()) { + log(LogType.MSG_IP_BAD_TYPE_SECRET); + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + + CanonicalizedPublicKeyRing canPublicRing; + boolean alreadyExists = false; + + // If there is an old keyring, merge it + try { + UncachedKeyRing oldPublicRing = getCanonicalizedPublicKeyRing(masterKeyId).getUncachedKeyRing(); + alreadyExists = true; + + // Merge data from new public ring into the old one + log(LogType.MSG_IP_MERGE_PUBLIC); + publicRing = oldPublicRing.merge(publicRing, mLog, mIndent); + + // If this is null, there is an error in the log so we can just return + if (publicRing == null) { + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + + // Canonicalize this keyring, to assert a number of assumptions made about it. + canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent); + if (canPublicRing == null) { + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + if (canKeyRings != null) canKeyRings.add(canPublicRing); + + // Early breakout if nothing changed + if (Arrays.hashCode(publicRing.getEncoded()) + == Arrays.hashCode(oldPublicRing.getEncoded())) { + log(LogType.MSG_IP_SUCCESS_IDENTICAL); + return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog, null); + } + } catch (NotFoundException e) { + // Not an issue, just means we are dealing with a new keyring. + + // Canonicalize this keyring, to assert a number of assumptions made about it. + canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, mIndent); + if (canPublicRing == null) { + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + if (canKeyRings != null) canKeyRings.add(canPublicRing); + } + + // If there is a secret key, merge new data (if any) and save the key for later + CanonicalizedSecretKeyRing canSecretRing; + try { + UncachedKeyRing secretRing = getCanonicalizedSecretKeyRing(publicRing.getMasterKeyId()) + .getUncachedKeyRing(); + + // Merge data from new public ring into secret one + log(LogType.MSG_IP_MERGE_SECRET); + secretRing = secretRing.merge(publicRing, mLog, mIndent); + if (secretRing == null) { + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + // This has always been a secret key ring, this is a safe cast + canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent); + if (canSecretRing == null) { + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + + } catch (NotFoundException e) { + // No secret key available (this is what happens most of the time) + canSecretRing = null; + } + + + // If we have an expected fingerprint, make sure it matches + if (expectedFingerprint != null) { + if (!canPublicRing.containsBoundSubkey(expectedFingerprint)) { + log(LogType.MSG_IP_FINGERPRINT_ERROR); + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } else { + log(LogType.MSG_IP_FINGERPRINT_OK); + } + } + + int result; + if (skipSave) { + // skip save method, set fixed result + result = SaveKeyringResult.SAVED_PUBLIC + | (alreadyExists ? SaveKeyringResult.UPDATED : 0); + } else { + result = saveCanonicalizedPublicKeyRing(canPublicRing, progress, canSecretRing != null); + } + + // Save the saved keyring (if any) + if (canSecretRing != null) { + progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100); + + int secretResult; + if (skipSave) { + // skip save method, set fixed result + secretResult = SaveKeyringResult.SAVED_SECRET; + } else { + secretResult = saveCanonicalizedSecretKeyRing(canSecretRing); + } + + if ((secretResult & SaveKeyringResult.RESULT_ERROR) != SaveKeyringResult.RESULT_ERROR) { + result |= SaveKeyringResult.SAVED_SECRET; + } + } + + return new SaveKeyringResult(result, mLog, canSecretRing); + } catch (IOException e) { + log(LogType.MSG_IP_ERROR_IO_EXC); + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } finally { + mIndent -= 1; + } + } + + public SaveKeyringResult savePublicKeyRing(UncachedKeyRing publicRing, Progressable progress, + String expectedFingerprint) { + return savePublicKeyRing(publicRing, progress, expectedFingerprint, null, false); + } + + public SaveKeyringResult savePublicKeyRing(UncachedKeyRing keyRing) { + return savePublicKeyRing(keyRing, new ProgressScaler(), null); + } + + public SaveKeyringResult saveSecretKeyRing(UncachedKeyRing secretRing, Progressable progress, + ArrayList canKeyRings, + boolean skipSave) { + + try { + long masterKeyId = secretRing.getMasterKeyId(); + log(LogType.MSG_IS, KeyFormattingUtils.convertKeyIdToHex(masterKeyId)); + mIndent += 1; + + if (!secretRing.isSecret()) { + log(LogType.MSG_IS_BAD_TYPE_PUBLIC); + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + + CanonicalizedSecretKeyRing canSecretRing; + boolean alreadyExists = false; + + // If there is an old secret key, merge it. + try { + UncachedKeyRing oldSecretRing = getCanonicalizedSecretKeyRing(masterKeyId).getUncachedKeyRing(); + alreadyExists = true; + + // Merge data from new secret ring into old one + log(LogType.MSG_IS_MERGE_SECRET); + secretRing = secretRing.merge(oldSecretRing, mLog, mIndent); + + // If this is null, there is an error in the log so we can just return + if (secretRing == null) { + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + + // Canonicalize this keyring, to assert a number of assumptions made about it. + // This is a safe cast, because we made sure this is a secret ring above + canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent); + if (canSecretRing == null) { + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + if (canKeyRings != null) canKeyRings.add(canSecretRing); + + // Early breakout if nothing changed + if (Arrays.hashCode(secretRing.getEncoded()) + == Arrays.hashCode(oldSecretRing.getEncoded())) { + log(LogType.MSG_IS_SUCCESS_IDENTICAL, + KeyFormattingUtils.convertKeyIdToHex(masterKeyId)); + return new SaveKeyringResult(SaveKeyringResult.UPDATED, mLog, null); + } + } catch (NotFoundException e) { + // Not an issue, just means we are dealing with a new keyring + + // Canonicalize this keyring, to assert a number of assumptions made about it. + // This is a safe cast, because we made sure this is a secret ring above + canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent); + if (canSecretRing == null) { + + // Special case: If keyring canonicalization failed, try again after adding + // all self-certificates from the public key. + try { + log(LogType.MSG_IS_MERGE_SPECIAL); + UncachedKeyRing oldPublicRing = getCanonicalizedPublicKeyRing(masterKeyId).getUncachedKeyRing(); + secretRing = secretRing.merge(oldPublicRing, mLog, mIndent); + canSecretRing = (CanonicalizedSecretKeyRing) secretRing.canonicalize(mLog, mIndent); + } catch (NotFoundException e2) { + // nothing, this is handled right in the next line + } + + if (canSecretRing == null) { + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + } + if (canKeyRings != null) canKeyRings.add(canSecretRing); + } + + // Merge new data into public keyring as well, if there is any + UncachedKeyRing publicRing; + try { + UncachedKeyRing oldPublicRing = getCanonicalizedPublicKeyRing(masterKeyId).getUncachedKeyRing(); + + // Merge data from new secret ring into public one + log(LogType.MSG_IS_MERGE_PUBLIC); + publicRing = oldPublicRing.merge(secretRing, mLog, mIndent); + if (publicRing == null) { + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + + } catch (NotFoundException e) { + log(LogType.MSG_IS_PUBRING_GENERATE); + publicRing = secretRing.extractPublicKeyRing(); + } + + CanonicalizedPublicKeyRing canPublicRing = (CanonicalizedPublicKeyRing) publicRing.canonicalize(mLog, + mIndent); + if (canPublicRing == null) { + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + + int publicResult; + if (skipSave) { + // skip save method, set fixed result + publicResult = SaveKeyringResult.SAVED_PUBLIC; + } else { + publicResult = saveCanonicalizedPublicKeyRing(canPublicRing, progress, true); + } + + if ((publicResult & SaveKeyringResult.RESULT_ERROR) == SaveKeyringResult.RESULT_ERROR) { + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } + + progress.setProgress(LogType.MSG_IP_REINSERT_SECRET.getMsgId(), 90, 100); + + int result; + if (skipSave) { + // skip save method, set fixed result + result = SaveKeyringResult.SAVED_SECRET + | (alreadyExists ? SaveKeyringResult.UPDATED : 0); + } else { + result = saveCanonicalizedSecretKeyRing(canSecretRing); + } + + return new SaveKeyringResult(result, mLog, canSecretRing); + } catch (IOException e) { + log(LogType.MSG_IS_ERROR_IO_EXC); + return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null); + } finally { + mIndent -= 1; + } + } + + public SaveKeyringResult saveSecretKeyRing(UncachedKeyRing secretRing, Progressable progress) { + return saveSecretKeyRing(secretRing, progress, null, false); + } + + @NonNull + public ConsolidateResult consolidateDatabaseStep1(Progressable progress) { + + OperationLog log = new OperationLog(); + int indent = 0; + + // 1a. fetch all secret keyrings into a cache file + log.add(LogType.MSG_CON, indent); + indent += 1; + + if (mConsolidateCritical) { + log.add(LogType.MSG_CON_RECURSIVE, indent); + return new ConsolidateResult(ConsolidateResult.RESULT_OK, log); + } + + progress.setProgress(R.string.progress_con_saving, 0, 100); + + // The consolidate operation can never be cancelled! + progress.setPreventCancel(); + + try { + + log.add(LogType.MSG_CON_SAVE_SECRET, indent); + indent += 1; + + final Cursor cursor = mContentResolver.query(KeyRingData.buildSecretKeyRingUri(), + new String[]{KeyRingData.KEY_RING_DATA}, null, null, null); + + if (cursor == null) { + log.add(LogType.MSG_CON_ERROR_DB, indent); + return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); + } + + // No keys existing might be a legitimate option, we write an empty file in that case + cursor.moveToFirst(); + ParcelableFileCache cache = + new ParcelableFileCache<>(mContext, "consolidate_secret.pcl"); + cache.writeCache(cursor.getCount(), new Iterator() { + ParcelableKeyRing ring; + + @Override + public boolean hasNext() { + if (ring != null) { + return true; + } + if (cursor.isAfterLast()) { + return false; + } + ring = new ParcelableKeyRing(cursor.getBlob(0)); + cursor.moveToNext(); + return true; + } + + @Override + public ParcelableKeyRing next() { + try { + return ring; + } finally { + ring = null; + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + }); + cursor.close(); + + } catch (IOException e) { + Log.e(Constants.TAG, "error saving secret", e); + log.add(LogType.MSG_CON_ERROR_IO_SECRET, indent); + return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); + } finally { + indent -= 1; + } + + progress.setProgress(R.string.progress_con_saving, 3, 100); + + // 1b. fetch all public keyrings into a cache file + try { + + log.add(LogType.MSG_CON_SAVE_PUBLIC, indent); + indent += 1; + + final Cursor cursor = mContentResolver.query( + KeyRingData.buildPublicKeyRingUri(), + new String[]{KeyRingData.KEY_RING_DATA}, null, null, null); + + if (cursor == null) { + log.add(LogType.MSG_CON_ERROR_DB, indent); + return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); + } + + // No keys existing might be a legitimate option, we write an empty file in that case + cursor.moveToFirst(); + ParcelableFileCache cache = + new ParcelableFileCache<>(mContext, "consolidate_public.pcl"); + cache.writeCache(cursor.getCount(), new Iterator() { + ParcelableKeyRing ring; + + @Override + public boolean hasNext() { + if (ring != null) { + return true; + } + if (cursor.isAfterLast()) { + return false; + } + ring = new ParcelableKeyRing(cursor.getBlob(0)); + cursor.moveToNext(); + return true; + } + + @Override + public ParcelableKeyRing next() { + try { + return ring; + } finally { + ring = null; + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + }); + cursor.close(); + + } catch (IOException e) { + Log.e(Constants.TAG, "error saving public", e); + log.add(LogType.MSG_CON_ERROR_IO_PUBLIC, indent); + return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); + } finally { + indent -= 1; + } + + log.add(LogType.MSG_CON_CRITICAL_IN, indent); + Preferences.getPreferences(mContext).setCachedConsolidate(true); + + return consolidateDatabaseStep2(log, indent, progress, false); + } + + @NonNull + public ConsolidateResult consolidateDatabaseStep2(Progressable progress) { + return consolidateDatabaseStep2(new OperationLog(), 0, progress, true); + } + + private static boolean mConsolidateCritical = false; + + @NonNull + private ConsolidateResult consolidateDatabaseStep2( + OperationLog log, int indent, Progressable progress, boolean recovery) { + + synchronized (DatabaseReadWriteInteractor.class) { + if (mConsolidateCritical) { + log.add(LogType.MSG_CON_ERROR_CONCURRENT, indent); + return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); + } + mConsolidateCritical = true; + } + + try { + Preferences prefs = Preferences.getPreferences(mContext); + + if (recovery) { + log.add(LogType.MSG_CON_RECOVER, indent); + indent += 1; + } + + if (!prefs.getCachedConsolidate()) { + log.add(LogType.MSG_CON_ERROR_BAD_STATE, indent); + return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); + } + + // 2. wipe database (IT'S DANGEROUS) + + // first, backup our list of updated key times + ArrayList updatedKeysValues = new ArrayList<>(); + final int INDEX_MASTER_KEY_ID = 0; + final int INDEX_LAST_UPDATED = 1; + Cursor lastUpdatedCursor = mContentResolver.query( + UpdatedKeys.CONTENT_URI, + new String[]{ + UpdatedKeys.MASTER_KEY_ID, + UpdatedKeys.LAST_UPDATED + }, + null, null, null); + while (lastUpdatedCursor.moveToNext()) { + ContentValues values = new ContentValues(); + values.put(UpdatedKeys.MASTER_KEY_ID, + lastUpdatedCursor.getLong(INDEX_MASTER_KEY_ID)); + values.put(UpdatedKeys.LAST_UPDATED, + lastUpdatedCursor.getLong(INDEX_LAST_UPDATED)); + updatedKeysValues.add(values); + } + lastUpdatedCursor.close(); + + log.add(LogType.MSG_CON_DB_CLEAR, indent); + mContentResolver.delete(KeyRings.buildUnifiedKeyRingsUri(), null, null); + + ParcelableFileCache cacheSecret, cachePublic; + + // Set flag that we have a cached consolidation here + try { + cacheSecret = new ParcelableFileCache<>(mContext, "consolidate_secret.pcl"); + IteratorWithSize itSecrets = cacheSecret.readCache(false); + int numSecrets = itSecrets.getSize(); + + log.add(LogType.MSG_CON_REIMPORT_SECRET, indent, numSecrets); + indent += 1; + + // 3. Re-Import secret keyrings from cache + if (numSecrets > 0) { + + ImportKeyResult result = new ImportOperation(mContext, this, + new ProgressFixedScaler(progress, 10, 25, 100, R.string.progress_con_reimport)) + .serialKeyRingImport(itSecrets, numSecrets, null, null, false); + log.add(result, indent); + } else { + log.add(LogType.MSG_CON_REIMPORT_SECRET_SKIP, indent); + } + + } catch (IOException e) { + Log.e(Constants.TAG, "error importing secret", e); + log.add(LogType.MSG_CON_ERROR_SECRET, indent); + return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); + } finally { + indent -= 1; + } + + try { + + cachePublic = new ParcelableFileCache<>(mContext, "consolidate_public.pcl"); + IteratorWithSize itPublics = cachePublic.readCache(); + int numPublics = itPublics.getSize(); + + log.add(LogType.MSG_CON_REIMPORT_PUBLIC, indent, numPublics); + indent += 1; + + // 4. Re-Import public keyrings from cache + if (numPublics > 0) { + + ImportKeyResult result = new ImportOperation(mContext, this, + new ProgressFixedScaler(progress, 25, 99, 100, R.string.progress_con_reimport)) + .serialKeyRingImport(itPublics, numPublics, null, null, false); + log.add(result, indent); + // re-insert our backed up list of updated key times + // TODO: can this cause issues in case a public key re-import failed? + mContentResolver.bulkInsert(UpdatedKeys.CONTENT_URI, + updatedKeysValues.toArray(new ContentValues[updatedKeysValues.size()])); + } else { + log.add(LogType.MSG_CON_REIMPORT_PUBLIC_SKIP, indent); + } + + } catch (IOException e) { + Log.e(Constants.TAG, "error importing public", e); + log.add(LogType.MSG_CON_ERROR_PUBLIC, indent); + return new ConsolidateResult(ConsolidateResult.RESULT_ERROR, log); + } finally { + indent -= 1; + } + + log.add(LogType.MSG_CON_CRITICAL_OUT, indent); + Preferences.getPreferences(mContext).setCachedConsolidate(false); + + // 5. Delete caches + try { + log.add(LogType.MSG_CON_DELETE_SECRET, indent); + indent += 1; + cacheSecret.delete(); + } catch (IOException e) { + // doesn't /really/ matter + Log.e(Constants.TAG, "IOException during delete of secret cache", e); + log.add(LogType.MSG_CON_WARN_DELETE_SECRET, indent); + } finally { + indent -= 1; + } + + try { + log.add(LogType.MSG_CON_DELETE_PUBLIC, indent); + indent += 1; + cachePublic.delete(); + } catch (IOException e) { + // doesn't /really/ matter + Log.e(Constants.TAG, "IOException during deletion of public cache", e); + log.add(LogType.MSG_CON_WARN_DELETE_PUBLIC, indent); + } finally { + indent -= 1; + } + + progress.setProgress(100, 100); + log.add(LogType.MSG_CON_SUCCESS, indent); + + return new ConsolidateResult(ConsolidateResult.RESULT_OK, log); + + } finally { + mConsolidateCritical = false; + } + + } + + /** + * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing + */ + private ContentProviderOperation + buildCertOperations(long masterKeyId, int rank, WrappedSignature cert, int verified) + throws IOException { + ContentValues values = new ContentValues(); + values.put(Certs.MASTER_KEY_ID, masterKeyId); + values.put(Certs.RANK, rank); + values.put(Certs.KEY_ID_CERTIFIER, cert.getKeyId()); + values.put(Certs.TYPE, cert.getSignatureType()); + values.put(Certs.CREATION, cert.getCreationTime().getTime() / 1000); + values.put(Certs.VERIFIED, verified); + values.put(Certs.DATA, cert.getEncoded()); + + Uri uri = Certs.buildCertsUri(masterKeyId); + + return ContentProviderOperation.newInsert(uri).withValues(values).build(); + } + + /** + * Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing + */ + private ContentProviderOperation + buildUserIdOperations(long masterKeyId, UserPacketItem item, int rank) { + ContentValues values = new ContentValues(); + values.put(UserPackets.MASTER_KEY_ID, masterKeyId); + values.put(UserPackets.TYPE, item.type); + values.put(UserPackets.USER_ID, item.userId); + values.put(UserPackets.NAME, item.name); + values.put(UserPackets.EMAIL, item.email); + values.put(UserPackets.COMMENT, item.comment); + values.put(UserPackets.ATTRIBUTE_DATA, item.attributeData); + values.put(UserPackets.IS_PRIMARY, item.isPrimary); + values.put(UserPackets.IS_REVOKED, item.selfRevocation != null); + values.put(UserPackets.RANK, rank); + + Uri uri = UserPackets.buildUserIdsUri(masterKeyId); + + return ContentProviderOperation.newInsert(uri).withValues(values).build(); + } + + public Uri renewKeyLastUpdatedTime(long masterKeyId, long time, TimeUnit timeUnit) { + ContentValues values = new ContentValues(); + values.put(UpdatedKeys.MASTER_KEY_ID, masterKeyId); + values.put(UpdatedKeys.LAST_UPDATED, timeUnit.toSeconds(time)); + + return mContentResolver.insert(UpdatedKeys.CONTENT_URI, values); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 167302440..d11dca6c7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -63,10 +63,10 @@ import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.ApiDataAccessObject; +import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.remote.OpenPgpServiceKeyIdExtractor.KeyIdResult; import org.sufficientlysecure.keychain.service.BackupKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -97,7 +97,7 @@ public class OpenPgpService extends Service { public void onCreate() { super.onCreate(); mApiPermissionHelper = new ApiPermissionHelper(this, new ApiDataAccessObject(this)); - mDatabaseInteractor = new DatabaseInteractor(this); + mDatabaseInteractor = new DatabaseInteractor(getContentResolver()); mApiDao = new ApiDataAccessObject(this); mApiPendingIntentFactory = new ApiPendingIntentFactory(getBaseContext()); @@ -167,7 +167,7 @@ public class OpenPgpService extends Service { } // execute PGP operation! - PgpSignEncryptOperation pse = new PgpSignEncryptOperation(this, new DatabaseInteractor(this), null); + PgpSignEncryptOperation pse = new PgpSignEncryptOperation(this, mDatabaseInteractor, null); PgpSignEncryptResult pgpResult = pse.execute(pseInput, inputParcel, inputData, outputStream); if (pgpResult.isPending()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RequestKeyPermissionPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RequestKeyPermissionPresenter.java index 467d51675..3fa66fa97 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RequestKeyPermissionPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RequestKeyPermissionPresenter.java @@ -15,6 +15,7 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.ApiDataAccessObject; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.provider.DatabaseInteractor.NotFoundException; @@ -40,7 +41,7 @@ class RequestKeyPermissionPresenter { PackageManager packageManager = context.getPackageManager(); ApiDataAccessObject apiDataAccessObject = new ApiDataAccessObject(context); ApiPermissionHelper apiPermissionHelper = new ApiPermissionHelper(context, apiDataAccessObject); - DatabaseInteractor databaseInteractor = new DatabaseInteractor(context); + DatabaseInteractor databaseInteractor = new DatabaseReadWriteInteractor(context); return new RequestKeyPermissionPresenter(context, apiDataAccessObject, apiPermissionHelper, packageManager, databaseInteractor); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java index c9b8f2103..470b19ec0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java @@ -48,7 +48,7 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.util.Log; @@ -111,36 +111,37 @@ public class KeychainService extends Service implements Progressable { // just for brevity KeychainService outerThis = KeychainService.this; + DatabaseReadWriteInteractor databaseInteractor = new DatabaseReadWriteInteractor(outerThis); if (inputParcel instanceof SignEncryptParcel) { - op = new SignEncryptOperation(outerThis, new DatabaseInteractor(outerThis), outerThis, mActionCanceled); + op = new SignEncryptOperation(outerThis, databaseInteractor, outerThis, mActionCanceled); } else if (inputParcel instanceof PgpDecryptVerifyInputParcel) { - op = new PgpDecryptVerifyOperation(outerThis, new DatabaseInteractor(outerThis), outerThis); + op = new PgpDecryptVerifyOperation(outerThis, databaseInteractor, outerThis); } else if (inputParcel instanceof SaveKeyringParcel) { - op = new EditKeyOperation(outerThis, new DatabaseInteractor(outerThis), outerThis, mActionCanceled); + op = new EditKeyOperation(outerThis, databaseInteractor, outerThis, mActionCanceled); } else if (inputParcel instanceof ChangeUnlockParcel) { - op = new ChangeUnlockOperation(outerThis, new DatabaseInteractor(outerThis), outerThis); + op = new ChangeUnlockOperation(outerThis, databaseInteractor, outerThis); } else if (inputParcel instanceof RevokeKeyringParcel) { - op = new RevokeOperation(outerThis, new DatabaseInteractor(outerThis), outerThis); + op = new RevokeOperation(outerThis, databaseInteractor, outerThis); } else if (inputParcel instanceof CertifyActionsParcel) { - op = new CertifyOperation(outerThis, new DatabaseInteractor(outerThis), outerThis, mActionCanceled); + op = new CertifyOperation(outerThis, databaseInteractor, outerThis, mActionCanceled); } else if (inputParcel instanceof DeleteKeyringParcel) { - op = new DeleteOperation(outerThis, new DatabaseInteractor(outerThis), outerThis); + op = new DeleteOperation(outerThis, databaseInteractor, outerThis); } else if (inputParcel instanceof PromoteKeyringParcel) { - op = new PromoteKeyOperation(outerThis, new DatabaseInteractor(outerThis), outerThis, mActionCanceled); + op = new PromoteKeyOperation(outerThis, databaseInteractor, outerThis, mActionCanceled); } else if (inputParcel instanceof ImportKeyringParcel) { - op = new ImportOperation(outerThis, new DatabaseInteractor(outerThis), outerThis, mActionCanceled); + op = new ImportOperation(outerThis, databaseInteractor, outerThis, mActionCanceled); } else if (inputParcel instanceof BackupKeyringParcel) { - op = new BackupOperation(outerThis, new DatabaseInteractor(outerThis), outerThis, mActionCanceled); + op = new BackupOperation(outerThis, databaseInteractor, outerThis, mActionCanceled); } else if (inputParcel instanceof UploadKeyringParcel) { - op = new UploadOperation(outerThis, new DatabaseInteractor(outerThis), outerThis, mActionCanceled); + op = new UploadOperation(outerThis, databaseInteractor, outerThis, mActionCanceled); } else if (inputParcel instanceof ConsolidateInputParcel) { - op = new ConsolidateOperation(outerThis, new DatabaseInteractor(outerThis), outerThis); + op = new ConsolidateOperation(outerThis, databaseInteractor, outerThis); } else if (inputParcel instanceof KeybaseVerificationParcel) { - op = new KeybaseVerificationOperation(outerThis, new DatabaseInteractor(outerThis), outerThis); + op = new KeybaseVerificationOperation(outerThis, databaseInteractor, outerThis); } else if (inputParcel instanceof InputDataParcel) { - op = new InputDataOperation(outerThis, new DatabaseInteractor(outerThis), outerThis); + op = new InputDataOperation(outerThis, databaseInteractor, outerThis); } else if (inputParcel instanceof BenchmarkInputParcel) { - op = new BenchmarkOperation(outerThis, new DatabaseInteractor(outerThis), outerThis); + op = new BenchmarkOperation(outerThis, databaseInteractor, outerThis); } else { throw new AssertionError("Unrecognized input parcel in KeychainService!"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java index 30e4387ef..986f6b1e9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java @@ -35,8 +35,8 @@ import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.operations.ImportOperation; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.network.NetworkReceiver; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity; @@ -320,7 +320,7 @@ public class KeyserverSyncAdapterService extends Service { private ImportKeyResult directUpdate(Context context, ArrayList keyList, CryptoInputParcel cryptoInputParcel) { Log.d(Constants.TAG, "Starting normal update"); - ImportOperation importOp = new ImportOperation(context, new DatabaseInteractor(context), null); + ImportOperation importOp = new ImportOperation(context, new DatabaseReadWriteInteractor(context), null); return importOp.execute( new ImportKeyringParcel(keyList, Preferences.getPreferences(context).getPreferredKeyserver()), @@ -380,7 +380,7 @@ public class KeyserverSyncAdapterService extends Service { new OperationResult.OperationLog()); } ImportKeyResult result = - new ImportOperation(context, new DatabaseInteractor(context), null, mCancelled) + new ImportOperation(context, new DatabaseReadWriteInteractor(context), null, mCancelled) .execute( new ImportKeyringParcel( keyWrapper, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index fb6f1e08b..254bee246 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -41,7 +41,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Preferences; @@ -224,7 +224,7 @@ public class PassphraseCacheService extends Service { /** * Internal implementation to get cached passphrase. */ - private Passphrase getCachedPassphraseImpl(long masterKeyId, long subKeyId) throws DatabaseInteractor.NotFoundException { + private Passphrase getCachedPassphraseImpl(long masterKeyId, long subKeyId) throws DatabaseReadWriteInteractor.NotFoundException { // on "none" key, just do nothing if (masterKeyId == Constants.key.none) { return null; @@ -245,16 +245,16 @@ public class PassphraseCacheService extends Service { + masterKeyId + ", subKeyId " + subKeyId); // get the type of key (from the database) - CachedPublicKeyRing keyRing = new DatabaseInteractor(this).getCachedPublicKeyRing(masterKeyId); + CachedPublicKeyRing keyRing = new DatabaseReadWriteInteractor(this).getCachedPublicKeyRing(masterKeyId); SecretKeyType keyType = keyRing.getSecretKeyType(subKeyId); switch (keyType) { case PASSPHRASE_EMPTY: return new Passphrase(""); case UNAVAILABLE: - throw new DatabaseInteractor.NotFoundException("secret key for this subkey is not available"); + throw new DatabaseReadWriteInteractor.NotFoundException("secret key for this subkey is not available"); case GNU_DUMMY: - throw new DatabaseInteractor.NotFoundException("secret key for stripped subkey is not available"); + throw new DatabaseReadWriteInteractor.NotFoundException("secret key for stripped subkey is not available"); } // get cached passphrase @@ -398,7 +398,7 @@ public class PassphraseCacheService extends Service { bundle.putParcelable(EXTRA_PASSPHRASE, passphrase); msg.setData(bundle); } - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { Log.e(Constants.TAG, "PassphraseCacheService: Passphrase for unknown key was requested!"); msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java index ad65fde71..400edd56c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java @@ -34,8 +34,8 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.experimental.SentenceConfirm; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.ui.base.LoaderFragment; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; @@ -213,7 +213,7 @@ public class CertifyFingerprintFragment extends LoaderFragment implements private void certify(Uri dataUri) { long keyId = 0; try { - keyId = new DatabaseInteractor(getActivity()) + keyId = new DatabaseReadWriteInteractor(getActivity()) .getCachedPublicKeyRing(dataUri) .extractOrGetMasterKeyId(); } catch (PgpKeyNotFoundException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index b44969b7c..fa26f1721 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -35,7 +35,7 @@ import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -68,7 +68,7 @@ public class CertifyKeyFragment .getLongExtra(CertifyKeyActivity.EXTRA_CERTIFY_KEY_ID, Constants.key.none); if (certifyKeyId != Constants.key.none) { try { - CachedPublicKeyRing key = (new DatabaseInteractor(getActivity())) + CachedPublicKeyRing key = (new DatabaseReadWriteInteractor(getActivity())) .getCachedPublicKeyRing(certifyKeyId); if (key.canCertify()) { mCertifyKeySpinner.setPreSelectedKeyId(certifyKeyId); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 84a39108d..fffcad7a5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -29,8 +29,8 @@ import android.support.v4.app.TaskStackBuilder; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.securitytoken.KeyFormat; import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -180,7 +180,7 @@ public class CreateKeyActivity extends BaseSecurityTokenActivity { if (containsKeys(mScannedFingerprints)) { try { long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mScannedFingerprints); - CachedPublicKeyRing ring = new DatabaseInteractor(this).getCachedPublicKeyRing(masterKeyId); + CachedPublicKeyRing ring = new DatabaseReadWriteInteractor(this).getCachedPublicKeyRing(masterKeyId); ring.getMasterKeyId(); Intent intent = new Intent(this, ViewKeyActivity.class); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java index a3e8c3fe2..1248c8f69 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -43,8 +43,8 @@ import org.sufficientlysecure.keychain.operations.results.UploadResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.UploadKeyringParcel; @@ -411,7 +411,7 @@ public class CreateKeyFinalFragment extends Fragment { CreateKeyActivity activity = (CreateKeyActivity) getActivity(); final SaveKeyringParcel changeKeyringParcel; - CachedPublicKeyRing key = (new DatabaseInteractor(activity)) + CachedPublicKeyRing key = (new DatabaseReadWriteInteractor(activity)) .getCachedPublicKeyRing(saveKeyResult.mMasterKeyId); try { changeKeyringParcel = new SaveKeyringParcel(key.getMasterKeyId(), key.getFingerprint()); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index 2bc84687e..f065df87e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -45,9 +45,9 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -192,7 +192,7 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager. try { Intent viewKeyIntent = new Intent(getActivity(), ViewKeyActivity.class); - long masterKeyId = new DatabaseInteractor(getActivity()).getCachedPublicKeyRing( + long masterKeyId = new DatabaseReadWriteInteractor(getActivity()).getCachedPublicKeyRing( KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(keyId) ).getMasterKeyId(); viewKeyIntent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java index 84d94586b..3e776d4af 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -41,6 +41,7 @@ import org.sufficientlysecure.keychain.keyimport.ParcelableHkpKeyserver; import org.sufficientlysecure.keychain.operations.results.DeleteResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.RevokeResult; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.DeleteKeyringParcel; @@ -89,7 +90,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { if (mMasterKeyIds.length == 1 && mHasSecret) { // if mMasterKeyIds.length == 0 we let the DeleteOperation respond try { - HashMap data = new DatabaseInteractor(this).getUnifiedData( + HashMap data = new DatabaseReadWriteInteractor(this).getUnifiedData( mMasterKeyIds[0], new String[]{ KeychainContract.KeyRings.NAME, KeychainContract.KeyRings.IS_REVOKED @@ -112,7 +113,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { } else { showRevokeDeleteDialog(name); } - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { Log.e(Constants.TAG, "Secret key to delete not found at DeleteKeyDialogActivity for " + mMasterKeyIds[0], e); @@ -269,7 +270,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { long masterKeyId = masterKeyIds[0]; try { - HashMap data = new DatabaseInteractor(activity).getUnifiedData( + HashMap data = new DatabaseReadWriteInteractor(activity).getUnifiedData( masterKeyId, new String[]{ KeychainContract.KeyRings.NAME, KeychainContract.KeyRings.HAS_ANY_SECRET @@ -293,7 +294,7 @@ public class DeleteKeyDialogActivity extends FragmentActivity { } else { mMainMessage.setText(getString(R.string.public_key_deletetion_confirmation, name)); } - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { dismiss(); return null; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditIdentitiesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditIdentitiesFragment.java index c34b2b994..ef998e5d4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditIdentitiesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditIdentitiesFragment.java @@ -49,9 +49,9 @@ import org.sufficientlysecure.keychain.operations.results.UploadResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.provider.DatabaseInteractor.NotFoundException; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.UploadKeyringParcel; @@ -170,7 +170,7 @@ public class EditIdentitiesFragment extends Fragment try { Uri secretUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(mDataUri); CachedPublicKeyRing keyRing = - new DatabaseInteractor(getActivity()).getCachedPublicKeyRing(secretUri); + new DatabaseReadWriteInteractor(getActivity()).getCachedPublicKeyRing(secretUri); long masterKeyId = keyRing.getMasterKeyId(); // check if this is a master secret key we can work with diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index c766472f4..902858ff6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -48,9 +48,9 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.provider.DatabaseInteractor.NotFoundException; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; @@ -203,7 +203,7 @@ public class EditKeyFragment extends QueueingCryptoOperationFragment return; } - DatabaseInteractor databaseInteractor = new DatabaseInteractor(activity); + DatabaseInteractor databaseInteractor = new DatabaseReadWriteInteractor(activity); Cursor cursor = databaseInteractor.getContentResolver().query( KeyRings.buildUnifiedKeyRingsUri(), new String[]{ KeyRings.FINGERPRINT diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index e0b4b1ba6..67fdf65ce 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -57,6 +57,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.provider.DatabaseInteractor.NotFoundException; @@ -112,7 +113,7 @@ public class PassphraseDialogActivity extends FragmentActivity { // handle empty passphrases by directly returning an empty crypto input parcel try { CachedPublicKeyRing pubRing = - new DatabaseInteractor(this).getCachedPublicKeyRing(requiredInput.getMasterKeyId()); + new DatabaseReadWriteInteractor(this).getCachedPublicKeyRing(requiredInput.getMasterKeyId()); // use empty passphrase for empty passphrase if (pubRing.getSecretKeyType(requiredInput.getSubKeyId()) == SecretKeyType.PASSPHRASE_EMPTY) { // also return passphrase back to activity @@ -231,7 +232,7 @@ public class PassphraseDialogActivity extends FragmentActivity { try { long subKeyId = mRequiredInput.getSubKeyId(); - DatabaseInteractor helper = new DatabaseInteractor(activity); + DatabaseInteractor helper = new DatabaseReadWriteInteractor(activity); CachedPublicKeyRing cachedPublicKeyRing = helper.getCachedPublicKeyRing( KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(subKeyId)); // yes the inner try/catch block is necessary, otherwise the final variable @@ -266,7 +267,7 @@ public class PassphraseDialogActivity extends FragmentActivity { throw new AssertionError("Unhandled SecretKeyType (should not happen)"); } - } catch (PgpKeyNotFoundException | DatabaseInteractor.NotFoundException e) { + } catch (PgpKeyNotFoundException | DatabaseReadWriteInteractor.NotFoundException e) { alert.setTitle(R.string.title_key_not_found); alert.setMessage(getString(R.string.key_not_found, mRequiredInput.getSubKeyId())); alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @@ -457,7 +458,7 @@ public class PassphraseDialogActivity extends FragmentActivity { Long subKeyId = mRequiredInput.getSubKeyId(); CanonicalizedSecretKeyRing secretKeyRing = - new DatabaseInteractor(getActivity()).getCanonicalizedSecretKeyRing( + new DatabaseReadWriteInteractor(getActivity()).getCanonicalizedSecretKeyRing( KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(subKeyId)); CanonicalizedSecretKey secretKeyToUnlock = secretKeyRing.getSecretKey(subKeyId); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java index 2f99a0b68..2369a7f08 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java @@ -28,6 +28,7 @@ import android.widget.ImageView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.ui.base.BaseActivity; @@ -74,7 +75,7 @@ public class QrCodeViewActivity extends BaseActivity { } }); - DatabaseInteractor databaseInteractor = new DatabaseInteractor(this); + DatabaseInteractor databaseInteractor = new DatabaseReadWriteInteractor(this); try { byte[] blob = (byte[]) databaseInteractor.getGenericData( KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri), @@ -102,7 +103,7 @@ public class QrCodeViewActivity extends BaseActivity { mQrCode.setImageBitmap(scaled); } }); - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { Log.e(Constants.TAG, "key not found!", e); Notify.create(this, R.string.error_key_not_found, Style.ERROR).show(); ActivityCompat.finishAfterTransition(QrCodeViewActivity.this); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java index 4dec17128..91c2645d9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java @@ -33,6 +33,7 @@ import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.operations.ImportOperation; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; @@ -105,7 +106,7 @@ public class SafeSlingerActivity extends BaseActivity // retrieve public key blob and start SafeSlinger Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(masterKeyId); try { - byte[] keyBlob = (byte[]) new DatabaseInteractor(this).getGenericData( + byte[] keyBlob = (byte[]) new DatabaseReadWriteInteractor(this).getGenericData( uri, KeychainContract.KeyRingData.KEY_RING_DATA, DatabaseInteractor.FIELD_TYPE_BLOB); Intent slingerIntent = new Intent(this, ExchangeActivity.class); @@ -114,7 +115,7 @@ public class SafeSlingerActivity extends BaseActivity slingerIntent.putExtra(ExchangeConfig.extra.USER_DATA, keyBlob); slingerIntent.putExtra(ExchangeConfig.extra.HOST_NAME, Constants.SAFESLINGER_SERVER); startActivityForResult(slingerIntent, REQUEST_CODE_SAFE_SLINGER); - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { Log.e(Constants.TAG, "personal key not found", e); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java index 94415e154..adc91fe8d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SecurityTokenOperationActivity.java @@ -35,6 +35,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.securitytoken.KeyType; @@ -193,12 +194,12 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity { throw new IOException(getString(R.string.error_wrong_security_token)); } - DatabaseInteractor databaseInteractor = new DatabaseInteractor(this); + DatabaseInteractor databaseInteractor = new DatabaseReadWriteInteractor(this); CanonicalizedPublicKeyRing publicKeyRing; try { publicKeyRing = databaseInteractor.getCanonicalizedPublicKeyRing( KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(mRequiredInput.getMasterKeyId())); - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { throw new IOException("Couldn't find subkey for key to token operation."); } @@ -232,13 +233,13 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenActivity { mSecurityTokenHelper.setPin(new Passphrase("123456")); mSecurityTokenHelper.setAdminPin(new Passphrase("12345678")); - DatabaseInteractor databaseInteractor = new DatabaseInteractor(this); + DatabaseInteractor databaseInteractor = new DatabaseReadWriteInteractor(this); CanonicalizedSecretKeyRing secretKeyRing; try { secretKeyRing = databaseInteractor.getCanonicalizedSecretKeyRing( KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(mRequiredInput.getMasterKeyId()) ); - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { throw new IOException("Couldn't find subkey for key to token operation."); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java index d60518efc..734f59b2f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.WrappedSignature; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; @@ -184,7 +185,7 @@ public class ViewCertActivity extends BaseActivity Intent viewIntent = new Intent(ViewCertActivity.this, ViewKeyActivity.class); try { - DatabaseInteractor databaseInteractor = new DatabaseInteractor(ViewCertActivity.this); + DatabaseInteractor databaseInteractor = new DatabaseReadWriteInteractor(ViewCertActivity.this); long signerMasterKeyId = databaseInteractor.getCachedPublicKeyRing( KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(mCertifierKeyId)).getMasterKeyId(); viewIntent.setData(KeyRings.buildGenericKeyRingUri(signerMasterKeyId)); 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 593d6597c..674978452 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -72,6 +72,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; @@ -185,7 +186,7 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mDatabaseInteractor = new DatabaseInteractor(this); + mDatabaseInteractor = new DatabaseReadWriteInteractor(this); mImportOpHelper = new CryptoOperationHelper<>(1, this, this, null); setTitle(null); @@ -400,7 +401,7 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements case R.id.menu_key_view_refresh: { try { updateFromKeyserver(mDataUri, mDatabaseInteractor); - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { Notify.create(this, R.string.error_key_not_found, Notify.Style.ERROR).show(); } return true; @@ -741,7 +742,7 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements return; } try { - long keyId = new DatabaseInteractor(this) + long keyId = new DatabaseReadWriteInteractor(this) .getCachedPublicKeyRing(dataUri) .extractOrGetMasterKeyId(); long[] encryptionKeyIds = new long[]{keyId}; @@ -765,7 +766,7 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements private void startSafeSlinger(Uri dataUri) { long keyId = 0; try { - keyId = new DatabaseInteractor(this) + keyId = new DatabaseReadWriteInteractor(this) .getCachedPublicKeyRing(dataUri) .extractOrGetMasterKeyId(); } catch (PgpKeyNotFoundException e) { @@ -1119,7 +1120,7 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity implements private void updateFromKeyserver(Uri dataUri, DatabaseInteractor databaseInteractor) - throws DatabaseInteractor.NotFoundException { + throws DatabaseReadWriteInteractor.NotFoundException { mIsRefreshing = true; mRefreshItem.setEnabled(false); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java index b84c2498b..9e72e5867 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java @@ -44,6 +44,7 @@ import com.astuetz.PagerSlidingTabStrip; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; @@ -88,7 +89,7 @@ public class ViewKeyAdvActivity extends BaseActivity implements } }); - mDatabaseInteractor = new DatabaseInteractor(this); + mDatabaseInteractor = new DatabaseReadWriteInteractor(this); mViewPager = (ViewPager) findViewById(R.id.pager); mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.sliding_tab_layout); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java index 046d96805..f7fb131f2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -56,6 +56,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; @@ -93,7 +94,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements View root = super.onCreateView(inflater, superContainer, savedInstanceState); View view = inflater.inflate(R.layout.view_key_adv_share_fragment, getContainer()); - DatabaseInteractor databaseInteractor = new DatabaseInteractor(ViewKeyAdvShareFragment.this.getActivity()); + DatabaseInteractor databaseInteractor = new DatabaseReadWriteInteractor(ViewKeyAdvShareFragment.this.getActivity()); mNfcHelper = new NfcHelper(getActivity(), databaseInteractor); mFingerprintView = (TextView) view.findViewById(R.id.view_key_fingerprint); @@ -200,7 +201,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements private void startSafeSlinger(Uri dataUri) { long keyId = 0; try { - keyId = new DatabaseInteractor(getActivity()) + keyId = new DatabaseReadWriteInteractor(getActivity()) .getCachedPublicKeyRing(dataUri) .extractOrGetMasterKeyId(); } catch (PgpKeyNotFoundException e) { @@ -216,7 +217,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements if (activity == null || mFingerprint == null) { return; } - DatabaseInteractor databaseInteractor = new DatabaseInteractor(activity); + DatabaseInteractor databaseInteractor = new DatabaseReadWriteInteractor(activity); try { String content = databaseInteractor.getKeyRingAsArmoredString( @@ -273,7 +274,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements } catch (PgpGeneralException | IOException e) { Log.e(Constants.TAG, "error processing key!", e); Notify.create(activity, R.string.error_key_processing, Notify.Style.ERROR).show(); - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { Log.e(Constants.TAG, "key not found!", e); Notify.create(activity, R.string.error_key_not_found, Notify.Style.ERROR).show(); } @@ -457,7 +458,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements private void uploadToKeyserver() { long keyId; try { - keyId = new DatabaseInteractor(getActivity()) + keyId = new DatabaseReadWriteInteractor(getActivity()) .getCachedPublicKeyRing(mDataUri) .extractOrGetMasterKeyId(); } catch (PgpKeyNotFoundException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index 13c981746..b6eb61adf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; @@ -74,7 +75,7 @@ public class ImportKeysAdapter extends RecyclerView.Adapter data) { @@ -95,7 +96,7 @@ public class ImportKeysAdapter extends RecyclerView.Adapter 0; - } catch (DatabaseInteractor.NotFoundException | PgpKeyNotFoundException ignored) { + } catch (DatabaseReadWriteInteractor.NotFoundException | PgpKeyNotFoundException ignored) { } mKeyStates[i] = keyState; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseSecurityTokenActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseSecurityTokenActivity.java index f8db70a95..5fc22ccd0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseSecurityTokenActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseSecurityTokenActivity.java @@ -37,8 +37,8 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -105,7 +105,7 @@ public abstract class BaseSecurityTokenActivity extends BaseActivity final long subKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mSecurityTokenFingerprints); try { - CachedPublicKeyRing ring = new DatabaseInteractor(this).getCachedPublicKeyRing( + CachedPublicKeyRing ring = new DatabaseReadWriteInteractor(this).getCachedPublicKeyRing( KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(subKeyId)); long masterKeyId = ring.getMasterKeyId(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdWizard.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdWizard.java index b9ea3a7f7..a7b8558b2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdWizard.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdWizard.java @@ -34,9 +34,9 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.util.Log; @@ -58,7 +58,7 @@ public class LinkedIdWizard extends BaseActivity { try { Uri uri = getIntent().getData(); uri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(uri); - CachedPublicKeyRing ring = new DatabaseInteractor(this).getCachedPublicKeyRing(uri); + CachedPublicKeyRing ring = new DatabaseReadWriteInteractor(this).getCachedPublicKeyRing(uri); if (!ring.hasAnySecret()) { Log.e(Constants.TAG, "Linked Identities can only be added to secret keys!"); finish(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java index 3aef420bd..908e9db3c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java @@ -35,6 +35,7 @@ import android.provider.Settings; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.ui.util.Notify; @@ -132,7 +133,7 @@ public class NfcHelper { blobUri, KeychainContract.KeyRingData.KEY_RING_DATA, DatabaseInteractor.FIELD_TYPE_BLOB); - } catch (DatabaseInteractor.NotFoundException e) { + } catch (DatabaseReadWriteInteractor.NotFoundException e) { Log.e(Constants.TAG, "key not found!", e); } diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/BackupOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/BackupOperationTest.java index 31bd6571c..72b8c8d21 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/BackupOperationTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/BackupOperationTest.java @@ -44,7 +44,7 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow; import org.sufficientlysecure.keychain.pgp.WrappedSignature; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; import org.sufficientlysecure.keychain.service.BackupKeyringParcel; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; @@ -135,7 +135,7 @@ public class BackupOperationTest { @Before public void setUp() { - DatabaseInteractor databaseInteractor = new DatabaseInteractor(RuntimeEnvironment.application); + DatabaseReadWriteInteractor databaseInteractor = new DatabaseReadWriteInteractor(RuntimeEnvironment.application); // don't log verbosely here, we're not here to test imports ShadowLog.stream = oldShadowStream; @@ -150,7 +150,7 @@ public class BackupOperationTest { @Test public void testExportAllLocalStripped() throws Exception { BackupOperation op = new BackupOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); // make sure there is a local cert (so the later checks that there are none are meaningful) assertTrue("second keyring has local certification", checkForLocal(mStaticRing2)); @@ -249,7 +249,7 @@ public class BackupOperationTest { when(spyApplication.getContentResolver()).thenReturn(mockResolver); BackupOperation op = new BackupOperation(spyApplication, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); BackupKeyringParcel parcel = new BackupKeyringParcel( new long[] { mStaticRing1.getMasterKeyId() }, false, false, true, fakeOutputUri); @@ -306,7 +306,7 @@ public class BackupOperationTest { { // export encrypted BackupOperation op = new BackupOperation(spyApplication, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); BackupKeyringParcel parcel = new BackupKeyringParcel( new long[] { mStaticRing1.getMasterKeyId() }, false, true, true, fakeOutputUri); @@ -324,7 +324,7 @@ public class BackupOperationTest { { PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(outStream.toByteArray()); input.setAllowSymmetricDecryption(true); diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/BenchmarkOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/BenchmarkOperationTest.java index 5dec61169..4bdff329c 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/BenchmarkOperationTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/BenchmarkOperationTest.java @@ -25,7 +25,7 @@ import org.junit.runner.RunWith; import org.robolectric.RuntimeEnvironment; import org.robolectric.shadows.ShadowLog; import org.sufficientlysecure.keychain.KeychainTestRunner; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.BenchmarkInputParcel; import java.io.PrintStream; @@ -47,7 +47,7 @@ public class BenchmarkOperationTest { @Test public void testBenchmark() throws Exception { BenchmarkOperation op = new BenchmarkOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); op.execute(new BenchmarkInputParcel(), null); } diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java index 398831920..0e21a8c33 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java @@ -34,8 +34,8 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; @@ -117,7 +117,7 @@ public class CertifyOperationTest { @Before public void setUp() throws Exception { - DatabaseInteractor databaseInteractor = new DatabaseInteractor(RuntimeEnvironment.application); + DatabaseReadWriteInteractor databaseInteractor = new DatabaseReadWriteInteractor(RuntimeEnvironment.application); // don't log verbosely here, we're not here to test imports ShadowLog.stream = oldShadowStream; @@ -132,7 +132,7 @@ public class CertifyOperationTest { @Test public void testSelfCertifyFlag() throws Exception { - CanonicalizedPublicKeyRing ring = new DatabaseInteractor(RuntimeEnvironment.application) + CanonicalizedPublicKeyRing ring = new DatabaseReadWriteInteractor(RuntimeEnvironment.application) .getCanonicalizedPublicKeyRing(mStaticRing1.getMasterKeyId()); Assert.assertEquals("secret key must be marked self-certified in database", // TODO this should be more correctly be VERIFIED_SELF at some point! @@ -143,10 +143,10 @@ public class CertifyOperationTest { @Test public void testCertifyId() throws Exception { CertifyOperation op = new CertifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null, null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null, null); { - CanonicalizedPublicKeyRing ring = new DatabaseInteractor(RuntimeEnvironment.application) + CanonicalizedPublicKeyRing ring = new DatabaseReadWriteInteractor(RuntimeEnvironment.application) .getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId()); Assert.assertEquals("public key must not be marked verified prior to certification", Certs.UNVERIFIED, ring.getVerified()); @@ -160,7 +160,7 @@ public class CertifyOperationTest { Assert.assertTrue("certification must succeed", result.success()); { - CanonicalizedPublicKeyRing ring = new DatabaseInteractor(RuntimeEnvironment.application) + CanonicalizedPublicKeyRing ring = new DatabaseReadWriteInteractor(RuntimeEnvironment.application) .getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId()); Assert.assertEquals("new key must be verified now", Certs.VERIFIED_SECRET, ring.getVerified()); @@ -171,10 +171,10 @@ public class CertifyOperationTest { @Test public void testCertifyAttribute() throws Exception { CertifyOperation op = new CertifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null, null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null, null); { - CanonicalizedPublicKeyRing ring = new DatabaseInteractor(RuntimeEnvironment.application) + CanonicalizedPublicKeyRing ring = new DatabaseReadWriteInteractor(RuntimeEnvironment.application) .getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId()); Assert.assertEquals("public key must not be marked verified prior to certification", Certs.UNVERIFIED, ring.getVerified()); @@ -188,7 +188,7 @@ public class CertifyOperationTest { Assert.assertTrue("certification must succeed", result.success()); { - CanonicalizedPublicKeyRing ring = new DatabaseInteractor(RuntimeEnvironment.application) + CanonicalizedPublicKeyRing ring = new DatabaseReadWriteInteractor(RuntimeEnvironment.application) .getCanonicalizedPublicKeyRing(mStaticRing2.getMasterKeyId()); Assert.assertEquals("new key must be verified now", Certs.VERIFIED_SECRET, ring.getVerified()); @@ -200,7 +200,7 @@ public class CertifyOperationTest { @Test public void testCertifySelf() throws Exception { CertifyOperation op = new CertifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null, null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null, null); CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId()); actions.add(new CertifyAction(mStaticRing1.getMasterKeyId(), @@ -217,7 +217,7 @@ public class CertifyOperationTest { public void testCertifyNonexistent() throws Exception { CertifyOperation op = new CertifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null, null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null, null); { CertifyActionsParcel actions = new CertifyActionsParcel(mStaticRing1.getMasterKeyId()); diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java index 5cb914448..b1c651b61 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java @@ -38,7 +38,7 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.PromoteKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; @@ -90,7 +90,7 @@ public class PromoteKeyOperationTest { @Before public void setUp() throws Exception { - DatabaseInteractor databaseInteractor = new DatabaseInteractor(RuntimeEnvironment.application); + DatabaseReadWriteInteractor databaseInteractor = new DatabaseReadWriteInteractor(RuntimeEnvironment.application); // don't log verbosely here, we're not here to test imports ShadowLog.stream = oldShadowStream; @@ -104,14 +104,14 @@ public class PromoteKeyOperationTest { @Test public void testPromote() throws Exception { PromoteKeyOperation op = new PromoteKeyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null, null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null, null); PromoteKeyResult result = op.execute(new PromoteKeyringParcel(mStaticRing.getMasterKeyId(), null, null), null); Assert.assertTrue("promotion must succeed", result.success()); { - CachedPublicKeyRing ring = new DatabaseInteractor(RuntimeEnvironment.application) + CachedPublicKeyRing ring = new DatabaseReadWriteInteractor(RuntimeEnvironment.application) .getCachedPublicKeyRing(mStaticRing.getMasterKeyId()); Assert.assertTrue("key must have a secret now", ring.hasAnySecret()); @@ -128,7 +128,7 @@ public class PromoteKeyOperationTest { @Test public void testPromoteDivert() throws Exception { PromoteKeyOperation op = new PromoteKeyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null, null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null, null); byte[] aid = Hex.decode("D2760001240102000000012345670000"); @@ -137,7 +137,7 @@ public class PromoteKeyOperationTest { Assert.assertTrue("promotion must succeed", result.success()); { - CanonicalizedSecretKeyRing ring = new DatabaseInteractor(RuntimeEnvironment.application) + CanonicalizedSecretKeyRing ring = new DatabaseReadWriteInteractor(RuntimeEnvironment.application) .getCanonicalizedSecretKeyRing(mStaticRing.getMasterKeyId()); for (CanonicalizedSecretKey key : ring.secretKeyIterator()) { @@ -153,7 +153,7 @@ public class PromoteKeyOperationTest { @Test public void testPromoteDivertSpecific() throws Exception { PromoteKeyOperation op = new PromoteKeyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null, null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null, null); byte[] aid = Hex.decode("D2760001240102000000012345670000"); @@ -167,7 +167,7 @@ public class PromoteKeyOperationTest { Assert.assertTrue("promotion must succeed", result.success()); { - CanonicalizedSecretKeyRing ring = new DatabaseInteractor(RuntimeEnvironment.application) + CanonicalizedSecretKeyRing ring = new DatabaseReadWriteInteractor(RuntimeEnvironment.application) .getCanonicalizedSecretKeyRing(mStaticRing.getMasterKeyId()); for (CanonicalizedSecretKey key : ring.secretKeyIterator()) { diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java index 19033606d..ad28dc7f6 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java @@ -37,7 +37,7 @@ import org.sufficientlysecure.keychain.KeychainTestRunner; import org.sufficientlysecure.keychain.operations.InputDataOperation; import org.sufficientlysecure.keychain.operations.results.InputDataResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; import org.sufficientlysecure.keychain.service.InputDataParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -126,7 +126,7 @@ public class InputDataOperationTest { when(spyApplication.getContentResolver()).thenReturn(mockResolver); InputDataOperation op = new InputDataOperation(spyApplication, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputDataParcel input = new InputDataParcel(fakeInputUri, null); @@ -306,7 +306,7 @@ public class InputDataOperationTest { when(spyApplication.getContentResolver()).thenReturn(mockResolver); InputDataOperation op = new InputDataOperation(spyApplication, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputDataParcel input = new InputDataParcel(FAKE_CONTENT_INPUT_URI_1, null); return op.execute(input, new CryptoInputParcel()); diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java index 4cab67f5d..1a9573c3c 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java @@ -40,8 +40,8 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; @@ -149,7 +149,7 @@ public class PgpEncryptDecryptTest { @Before public void setUp() { - DatabaseInteractor databaseInteractor = new DatabaseInteractor(RuntimeEnvironment.application); + DatabaseReadWriteInteractor databaseInteractor = new DatabaseReadWriteInteractor(RuntimeEnvironment.application); // don't log verbosely here, we're not here to test imports ShadowLog.stream = oldShadowStream; @@ -172,7 +172,7 @@ public class PgpEncryptDecryptTest { ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes()); PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputData data = new InputData(in, in.available()); @@ -197,7 +197,7 @@ public class PgpEncryptDecryptTest { InputData data = new InputData(in, in.available()); PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(); input.setAllowSymmetricDecryption(true); DecryptVerifyResult result = op.execute( @@ -227,7 +227,7 @@ public class PgpEncryptDecryptTest { InputData data = new InputData(in, in.available()); PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(); input.setAllowSymmetricDecryption(true); DecryptVerifyResult result = op.execute(input, @@ -249,7 +249,7 @@ public class PgpEncryptDecryptTest { InputData data = new InputData(in, in.available()); PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(); input.setAllowSymmetricDecryption(true); DecryptVerifyResult result = op.execute(input, @@ -270,7 +270,7 @@ public class PgpEncryptDecryptTest { InputData data = new InputData(in, in.available()); PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(); input.setAllowSymmetricDecryption(false); DecryptVerifyResult result = op.execute(input, @@ -297,7 +297,7 @@ public class PgpEncryptDecryptTest { ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes()); PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputData data = new InputData(in, in.available()); @@ -353,7 +353,7 @@ public class PgpEncryptDecryptTest { ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes()); PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputData data = new InputData(in, in.available()); @@ -415,7 +415,7 @@ public class PgpEncryptDecryptTest { ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes()); PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputData data = new InputData(in, in.available()); @@ -472,7 +472,7 @@ public class PgpEncryptDecryptTest { ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes()); PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputData data = new InputData(in, in.available()); @@ -575,7 +575,7 @@ public class PgpEncryptDecryptTest { ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes()); PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputData data = new InputData(in, in.available()); @@ -626,11 +626,11 @@ public class PgpEncryptDecryptTest { new ArrayList(), new ArrayList(), new CryptoInputParcel(new Date(), mKeyPhrase1)); - DatabaseInteractor databaseInteractor = new DatabaseInteractor(RuntimeEnvironment.application); + DatabaseReadWriteInteractor databaseInteractor = new DatabaseReadWriteInteractor(RuntimeEnvironment.application); databaseInteractor.saveSecretKeyRing(modified, new ProgressScaler()); PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(ciphertext); DecryptVerifyResult result = op.execute(input, new CryptoInputParcel(mKeyPhrase1)); @@ -648,11 +648,11 @@ public class PgpEncryptDecryptTest { new ArrayList(), new ArrayList(), new CryptoInputParcel(new Date(), mKeyPhrase1)); - DatabaseInteractor databaseInteractor = new DatabaseInteractor(RuntimeEnvironment.application); + DatabaseReadWriteInteractor databaseInteractor = new DatabaseReadWriteInteractor(RuntimeEnvironment.application); databaseInteractor.saveSecretKeyRing(modified, new ProgressScaler()); PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(ciphertext); DecryptVerifyResult result = op.execute(input, new CryptoInputParcel(mKeyPhrase1)); @@ -675,7 +675,7 @@ public class PgpEncryptDecryptTest { new ArrayList(), new ArrayList(), new CryptoInputParcel(new Date(), mKeyPhrase1)); - DatabaseInteractor databaseInteractor = new DatabaseInteractor(RuntimeEnvironment.application); + DatabaseReadWriteInteractor databaseInteractor = new DatabaseReadWriteInteractor(RuntimeEnvironment.application); databaseInteractor.saveSecretKeyRing(modified, new ProgressScaler()); } @@ -685,7 +685,7 @@ public class PgpEncryptDecryptTest { ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes()); PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputData data = new InputData(in, in.available()); @@ -730,7 +730,7 @@ public class PgpEncryptDecryptTest { ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes()); PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputData data = new InputData(in, in.available()); @@ -824,7 +824,7 @@ public class PgpEncryptDecryptTest { { // decryption with passphrase cached should succeed for the other key if first is gone // delete first key from database - new DatabaseInteractor(RuntimeEnvironment.application).getContentResolver().delete( + new DatabaseReadWriteInteractor(RuntimeEnvironment.application).getContentResolver().delete( KeyRingData.buildPublicKeyRingUri(mStaticRing1.getMasterKeyId()), null, null ); @@ -859,7 +859,7 @@ public class PgpEncryptDecryptTest { ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes()); PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputData data = new InputData(in, in.available()); @@ -907,7 +907,7 @@ public class PgpEncryptDecryptTest { { // decryption with passphrase cached should succeed for the other key if first is gone // delete first key from database - new DatabaseInteractor(RuntimeEnvironment.application).getContentResolver().delete( + new DatabaseReadWriteInteractor(RuntimeEnvironment.application).getContentResolver().delete( KeyRingData.buildPublicKeyRingUri(mStaticRing1.getMasterKeyId()), null, null ); @@ -946,7 +946,7 @@ public class PgpEncryptDecryptTest { ByteArrayInputStream in = new ByteArrayInputStream(plaindata); PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputData data = new InputData(in, in.available()); @@ -1018,7 +1018,7 @@ public class PgpEncryptDecryptTest { ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes()); PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null); + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null); InputData data = new InputData(in, in.available()); @@ -1069,7 +1069,7 @@ public class PgpEncryptDecryptTest { final Passphrase passphrase, final Long checkMasterKeyId, final Long checkSubKeyId) { return new PgpDecryptVerifyOperation(RuntimeEnvironment.application, - new DatabaseInteractor(RuntimeEnvironment.application), null) { + new DatabaseReadWriteInteractor(RuntimeEnvironment.application), null) { @Override public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException { diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/provider/DatabaseInteractorSaveTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/provider/DatabaseInteractorSaveTest.java index a4f31581e..695158787 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/provider/DatabaseInteractorSaveTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/provider/DatabaseInteractorSaveTest.java @@ -43,7 +43,7 @@ import java.util.Iterator; @RunWith(KeychainTestRunner.class) public class DatabaseInteractorSaveTest { - DatabaseInteractor mDatabaseInteractor = new DatabaseInteractor(RuntimeEnvironment.application); + DatabaseReadWriteInteractor mDatabaseInteractor = new DatabaseReadWriteInteractor(RuntimeEnvironment.application); @BeforeClass public static void setUpOnce() throws Exception { @@ -61,17 +61,17 @@ public class DatabaseInteractorSaveTest { SaveKeyringResult result; // insert both keys, second should fail - result = new DatabaseInteractor(RuntimeEnvironment.application).savePublicKeyRing(first); + result = new DatabaseReadWriteInteractor(RuntimeEnvironment.application).savePublicKeyRing(first); Assert.assertTrue("first keyring import should succeed", result.success()); - result = new DatabaseInteractor(RuntimeEnvironment.application).savePublicKeyRing(second); + result = new DatabaseReadWriteInteractor(RuntimeEnvironment.application).savePublicKeyRing(second); Assert.assertFalse("second keyring import should fail", result.success()); new KeychainDatabase(RuntimeEnvironment.application).clearDatabase(); // and the other way around - result = new DatabaseInteractor(RuntimeEnvironment.application).savePublicKeyRing(second); + result = new DatabaseReadWriteInteractor(RuntimeEnvironment.application).savePublicKeyRing(second); Assert.assertTrue("first keyring import should succeed", result.success()); - result = new DatabaseInteractor(RuntimeEnvironment.application).savePublicKeyRing(first); + result = new DatabaseReadWriteInteractor(RuntimeEnvironment.application).savePublicKeyRing(first); Assert.assertFalse("second keyring import should fail", result.success()); } @@ -90,13 +90,13 @@ public class DatabaseInteractorSaveTest { SaveKeyringResult result; // insert secret, this should fail because of missing self-cert - result = new DatabaseInteractor(RuntimeEnvironment.application).saveSecretKeyRing(seckey, new ProgressScaler()); + result = new DatabaseReadWriteInteractor(RuntimeEnvironment.application).saveSecretKeyRing(seckey, new ProgressScaler()); Assert.assertFalse("secret keyring import before pubring import should fail", result.success()); // insert pubkey, then seckey - both should succeed - result = new DatabaseInteractor(RuntimeEnvironment.application).savePublicKeyRing(pubkey); + result = new DatabaseReadWriteInteractor(RuntimeEnvironment.application).savePublicKeyRing(pubkey); Assert.assertTrue("public keyring import should succeed", result.success()); - result = new DatabaseInteractor(RuntimeEnvironment.application).saveSecretKeyRing(seckey, new ProgressScaler()); + result = new DatabaseReadWriteInteractor(RuntimeEnvironment.application).saveSecretKeyRing(seckey, new ProgressScaler()); Assert.assertTrue("secret keyring import after pubring import should succeed", result.success()); } diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/provider/InteropTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/provider/InteropTest.java index a8a03d390..c1f4da4bf 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/provider/InteropTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/provider/InteropTest.java @@ -243,7 +243,7 @@ public class InteropTest { final Uri verifyUri = verify != null ? KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(verify.getMasterKeyId()) : null; - DatabaseInteractor helper = new DatabaseInteractor(RuntimeEnvironment.application) { + DatabaseReadWriteInteractor helper = new DatabaseReadWriteInteractor(RuntimeEnvironment.application) { @Override public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) throws PgpKeyNotFoundException { diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/remote/KeychainExternalProviderTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/remote/KeychainExternalProviderTest.java index d72102005..8188023cc 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/remote/KeychainExternalProviderTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/remote/KeychainExternalProviderTest.java @@ -20,8 +20,8 @@ import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.provider.ApiDataAccessObject; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.provider.DatabaseInteractorSaveTest; import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; @@ -45,7 +45,7 @@ public class KeychainExternalProviderTest { static final long KEY_ID_PUBLIC = 0x9A282CE2AB44A382L; - DatabaseInteractor databaseInteractor = new DatabaseInteractor(RuntimeEnvironment.application); + DatabaseReadWriteInteractor databaseInteractor = new DatabaseReadWriteInteractor(RuntimeEnvironment.application); ContentResolver contentResolver = RuntimeEnvironment.application.getContentResolver(); ApiPermissionHelper apiPermissionHelper; ApiDataAccessObject apiDao; diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/support/DatabaseInteractorStub.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/support/DatabaseInteractorStub.java index f2ea24281..4947aff30 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/support/DatabaseInteractorStub.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/support/DatabaseInteractorStub.java @@ -21,9 +21,10 @@ import android.content.Context; import android.net.Uri; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; -import org.sufficientlysecure.keychain.provider.DatabaseInteractor; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; -class DatabaseInteractorStub extends DatabaseInteractor { + +class DatabaseInteractorStub extends DatabaseReadWriteInteractor { public DatabaseInteractorStub(Context context) { super(context); } diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java index e2756747f..86c908dc0 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/support/KeyringTestingHelper.java @@ -25,6 +25,7 @@ import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.DatabaseInteractor; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; +import org.sufficientlysecure.keychain.provider.DatabaseReadWriteInteractor; import org.sufficientlysecure.keychain.util.ProgressScaler; import java.io.ByteArrayInputStream; @@ -50,7 +51,7 @@ public class KeyringTestingHelper { public boolean addKeyring(Collection blobFiles) throws Exception { - DatabaseInteractor databaseInteractor = new DatabaseInteractor(context); + DatabaseReadWriteInteractor databaseInteractor = new DatabaseReadWriteInteractor(context); byte[] data = TestDataUtil.readAllFully(blobFiles); UncachedKeyRing ring = UncachedKeyRing.decodeFromData(data); @@ -349,7 +350,7 @@ public class KeyringTestingHelper { try { databaseInteractor.getCanonicalizedPublicKeyRing(masterKeyId); throw new AssertionError("Was expecting the previous call to fail!"); - } catch (DatabaseInteractor.NotFoundException expectedException) { + } catch (DatabaseReadWriteInteractor.NotFoundException expectedException) { // good } }