diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/KeyRingDao.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/KeyRingDao.java deleted file mode 100644 index 98298a094..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/KeyRingDao.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.sufficientlysecure.keychain.livedata; - - -import java.util.ArrayList; -import java.util.List; - -import android.arch.persistence.db.SupportSQLiteDatabase; -import android.content.Context; -import android.database.Cursor; - -import com.squareup.sqldelight.SqlDelightQuery; -import org.sufficientlysecure.keychain.model.SubKey; -import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; -import org.sufficientlysecure.keychain.provider.KeychainDatabase; - - -public class KeyRingDao { - private final SupportSQLiteDatabase db; - - public static KeyRingDao getInstance(Context context) { - KeychainDatabase keychainDatabase = new KeychainDatabase(context); - - return new KeyRingDao(keychainDatabase.getWritableDatabase()); - } - - private KeyRingDao(SupportSQLiteDatabase writableDatabase) { - this.db = writableDatabase; - } - - public List getUnifiedKeyInfo() { - SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfo(); - List result = new ArrayList<>(); - try (Cursor cursor = db.query(query)) { - while (cursor.moveToNext()) { - UnifiedKeyInfo unifiedKeyInfo = SubKey.UNIFIED_KEY_INFO_MAPPER.map(cursor); - result.add(unifiedKeyInfo); - } - } - return result; - } -} 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 3559ea2a4..3e77ef6f0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java @@ -30,7 +30,6 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.provider.KeyRepository; -import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.util.Passphrase; @@ -113,15 +112,14 @@ public abstract class BaseOperation implements PassphraseC @Override public Passphrase getCachedPassphrase(long subKeyId) throws NoSecretKeyException { - try { - if (subKeyId != key.symmetric) { - long masterKeyId = mKeyRepository.getMasterKeyId(subKeyId); - return getCachedPassphrase(masterKeyId, subKeyId); + if (subKeyId != key.symmetric) { + Long masterKeyId = mKeyRepository.getMasterKeyIdBySubkeyId(subKeyId); + if (masterKeyId == null) { + throw new PassphraseCacheInterface.NoSecretKeyException(); } - return getCachedPassphrase(key.symmetric, key.symmetric); - } catch (NotFoundException e) { - throw new PassphraseCacheInterface.NoSecretKeyException(); + return getCachedPassphrase(masterKeyId, subKeyId); } + return getCachedPassphrase(key.symmetric, key.symmetric); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyRepository.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyRepository.java index ce89cc977..aa51707f4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyRepository.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyRepository.java @@ -33,6 +33,7 @@ import com.squareup.sqldelight.SqlDelightQuery; import org.bouncycastle.bcpg.ArmoredOutputStream; import org.sufficientlysecure.keychain.model.KeyRingPublic; import org.sufficientlysecure.keychain.model.SubKey; +import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UserPacket; import org.sufficientlysecure.keychain.model.UserPacket.UserId; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; @@ -172,7 +173,7 @@ public class KeyRepository extends AbstractDao { return getGenericData(KeyRings.buildUnifiedKeyRingUri(masterKeyId), proj, types); } - public long getMasterKeyId(long subKeyId) throws NotFoundException { + public long getMasterKeyIdBySubKeyId(long subKeyId) throws NotFoundException { return (Long) getGenericData(KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(subKeyId), KeyRings.MASTER_KEY_ID, FIELD_TYPE_INTEGER); } @@ -238,6 +239,33 @@ public class KeyRepository extends AbstractDao { } } + public List getAllMasterKeyIds() { + SqlDelightQuery query = KeyRingPublic.FACTORY.selectAllMasterKeyIds(); + return mapAllRows(query, KeyRingPublic.FACTORY.selectAllMasterKeyIdsMapper()::map); + } + + public List getMasterKeyIdsBySigner(List signerMasterKeyIds) { + long[] signerKeyIds = new long[signerMasterKeyIds.size()]; + int i = 0; + for (Long signerKeyId : signerMasterKeyIds) { + signerKeyIds[i++] = signerKeyId; + } + SqlDelightQuery query = SubKey.FACTORY.selectMasterKeyIdsBySigner(signerKeyIds); + return mapAllRows(query, KeyRingPublic.FACTORY.selectAllMasterKeyIdsMapper()::map); + } + + public List getUnifiedKeyInfo() { + SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfo(); + List result = new ArrayList<>(); + try (Cursor cursor = getReadableDb().query(query)) { + while (cursor.moveToNext()) { + UnifiedKeyInfo unifiedKeyInfo = SubKey.UNIFIED_KEY_INFO_MAPPER.map(cursor); + result.add(unifiedKeyInfo); + } + } + return result; + } + public List getUserIds(long... masterKeyIds) { SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyIds); return mapAllRows(query, UserPacket.USER_ID_MAPPER::map); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyWritableRepository.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyWritableRepository.java index 7cabe3de5..008af6e31 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyWritableRepository.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyWritableRepository.java @@ -1013,30 +1013,18 @@ public class KeyWritableRepository extends KeyRepository { log.add(LogType.MSG_TRUST, 0); - Cursor cursor; Preferences preferences = Preferences.getPreferences(context); boolean isTrustDbInitialized = preferences.isKeySignaturesTableInitialized(); + + List masterKeyIds; if (!isTrustDbInitialized) { log.add(LogType.MSG_TRUST_INITIALIZE, 1); - cursor = contentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), - new String[] { KeyRings.MASTER_KEY_ID }, null, null, null); + masterKeyIds = getAllMasterKeyIds(); } else { - String[] signerMasterKeyIdStrings = new String[signerMasterKeyIds.size()]; - int i = 0; - for (Long masterKeyId : signerMasterKeyIds) { - log.add(LogType.MSG_TRUST_KEY, 1, KeyFormattingUtils.beautifyKeyId(masterKeyId)); - signerMasterKeyIdStrings[i++] = Long.toString(masterKeyId); - } - - cursor = contentResolver.query(KeyRings.buildUnifiedKeyRingsFilterBySigner(), - new String[] { KeyRings.MASTER_KEY_ID }, null, signerMasterKeyIdStrings, null); + masterKeyIds = getMasterKeyIdsBySigner(signerMasterKeyIds); } - if (cursor == null) { - throw new IllegalStateException(); - } - - int totalKeys = cursor.getCount(); + int totalKeys = masterKeyIds.size(); int processedKeys = 0; if (totalKeys == 0) { @@ -1046,34 +1034,30 @@ public class KeyWritableRepository extends KeyRepository { log.add(LogType.MSG_TRUST_COUNT, 1, totalKeys); } - try { - while (cursor.moveToNext()) { - try { - long masterKeyId = cursor.getLong(0); + for (long masterKeyId : masterKeyIds) { + try { + log.add(LogType.MSG_TRUST_KEY, 1, KeyFormattingUtils.beautifyKeyId(masterKeyId)); - byte[] pubKeyData = loadPublicKeyRingData(masterKeyId); - UncachedKeyRing uncachedKeyRing = UncachedKeyRing.decodeFromData(pubKeyData); + byte[] pubKeyData = loadPublicKeyRingData(masterKeyId); + UncachedKeyRing uncachedKeyRing = UncachedKeyRing.decodeFromData(pubKeyData); - clearLog(); - SaveKeyringResult result = savePublicKeyRing(uncachedKeyRing, true); + clearLog(); + SaveKeyringResult result = savePublicKeyRing(uncachedKeyRing, true); - log.add(result, 1); - progress.setProgress(processedKeys++, totalKeys); - } catch (NotFoundException | PgpGeneralException | IOException e) { - Timber.e(e, "Error updating trust database"); - return new UpdateTrustResult(UpdateTrustResult.RESULT_ERROR, log); - } + log.add(result, 1); + progress.setProgress(processedKeys++, totalKeys); + } catch (NotFoundException | PgpGeneralException | IOException e) { + Timber.e(e, "Error updating trust database"); + return new UpdateTrustResult(UpdateTrustResult.RESULT_ERROR, log); } - - if (!isTrustDbInitialized) { - preferences.setKeySignaturesTableInitialized(); - } - - log.add(LogType.MSG_TRUST_OK, 1); - return new UpdateTrustResult(UpdateTrustResult.RESULT_OK, log); - } finally { - cursor.close(); } + + if (!isTrustDbInitialized) { + preferences.setKeySignaturesTableInitialized(); + } + + log.add(LogType.MSG_TRUST_OK, 1); + return new UpdateTrustResult(UpdateTrustResult.RESULT_OK, log); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index 0a39dc397..7c07174d8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -104,9 +104,6 @@ public class KeychainContract { public static final String PATH_BY_SUBKEY = "subkey"; public static final String PATH_BY_USER_ID = "user_id"; - public static final String PATH_FILTER = "filter"; - public static final String PATH_BY_SIGNER = "signer"; - public static final String PATH_PUBLIC = "public"; public static final String PATH_USER_IDS = "user_ids"; public static final String PATH_KEYS = "keys"; @@ -170,10 +167,6 @@ public class KeychainContract { return CONTENT_URI.buildUpon().appendPath(PATH_FIND) .appendPath(PATH_BY_SUBKEY).appendPath(Long.toString(subkey)).build(); } - - public static Uri buildUnifiedKeyRingsFilterBySigner() { - return CONTENT_URI.buildUpon().appendPath(PATH_FILTER).appendPath(PATH_BY_SIGNER).build(); - } } public static class KeyRingData implements KeyRingsColumns, BaseColumns { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index 5e0e8e2b6..2363bffe9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.CertsModel; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.KeyMetadataModel; import org.sufficientlysecure.keychain.KeyRingsPublicModel; +import org.sufficientlysecure.keychain.KeySignaturesModel; import org.sufficientlysecure.keychain.UserPacketsModel; import org.sufficientlysecure.keychain.model.ApiApp; import org.sufficientlysecure.keychain.model.Certification; @@ -199,7 +200,7 @@ public class KeychainDatabase { db.execSQL(UserPacketsModel.CREATE_TABLE); db.execSQL(CertsModel.CREATE_TABLE); db.execSQL(KeyMetadataModel.CREATE_TABLE); - db.execSQL(CREATE_KEY_SIGNATURES); + db.execSQL(KeySignaturesModel.CREATE_TABLE); db.execSQL(CREATE_API_APPS_ALLOWED_KEYS); db.execSQL(CREATE_OVERRIDDEN_WARNINGS); db.execSQL(AutocryptPeersModel.CREATE_TABLE); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 40fae66eb..1e4534125 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -65,7 +65,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe private static final int KEY_RINGS_FIND_BY_EMAIL = 400; private static final int KEY_RINGS_FIND_BY_SUBKEY = 401; private static final int KEY_RINGS_FIND_BY_USER_ID = 402; - private static final int KEY_RINGS_FILTER_BY_SIGNER = 403; private static final int KEY_SIGNATURES = 700; @@ -108,9 +107,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_USER_ID + "/*", KEY_RINGS_FIND_BY_USER_ID); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" - + KeychainContract.PATH_FILTER + "/" + KeychainContract.PATH_BY_SIGNER, - KEY_RINGS_FILTER_BY_SIGNER); /* * list key_ring specifics @@ -191,8 +187,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe case KEY_RINGS_UNIFIED: case KEY_RINGS_FIND_BY_EMAIL: case KEY_RINGS_FIND_BY_SUBKEY: - case KEY_RINGS_FIND_BY_USER_ID: - case KEY_RINGS_FILTER_BY_SIGNER: { + case KEY_RINGS_FIND_BY_USER_ID: { HashMap projectionMap = new HashMap<>(); projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id"); projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID); @@ -356,23 +351,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe } break; } - case KEY_RINGS_FILTER_BY_SIGNER: { - StringBuilder signerKeyIds = new StringBuilder(); - signerKeyIds.append(selectionArgs[0]); - for (int i = 1; i < selectionArgs.length; i++) { - signerKeyIds.append(',').append(selectionArgs[i]); - } - - qb.appendWhere(" AND EXISTS (SELECT 1 FROM " + Tables.KEY_SIGNATURES + " WHERE " + - Tables.KEY_SIGNATURES + "." + KeySignatures.MASTER_KEY_ID + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + - " AND " + - Tables.KEY_SIGNATURES + "." + KeySignatures.SIGNER_KEY_ID + " IN (" + signerKeyIds + ")" + - ")"); - - selection = null; - selectionArgs = null; - break; - } case KEY_RINGS_FIND_BY_EMAIL: case KEY_RINGS_FIND_BY_USER_ID: { String chunks[] = uri.getLastPathSegment().split(" *, *"); 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 0069278d5..fe9eaf710 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -196,7 +196,8 @@ public abstract class DecryptFragment extends Fragment implements LoaderManager. try { Intent viewKeyIntent = new Intent(getActivity(), ViewKeyActivity.class); - long masterKeyId = KeyRepository.create(getContext()).getCachedPublicKeyRing( + KeyRepository keyRepository = KeyRepository.create(requireContext()); + long masterKeyId = keyRepository.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 7d13280ce..d6afada2f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -86,7 +86,8 @@ public class DeleteKeyDialogActivity extends FragmentActivity { if (mMasterKeyIds.length == 1 && mHasSecret) { // if mMasterKeyIds.length == 0 we let the DeleteOperation respond try { - HashMap data = KeyRepository.create(this).getUnifiedData( + KeyRepository keyRepository = KeyRepository.create(this); + HashMap data = keyRepository.getUnifiedData( mMasterKeyIds[0], new String[]{ KeychainContract.KeyRings.NAME, KeychainContract.KeyRings.IS_REVOKED diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 4a202043c..357eb44fd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -58,11 +58,11 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.keysync.KeyserverSyncManager; -import org.sufficientlysecure.keychain.livedata.KeyRingDao; import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.operations.results.BenchmarkResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.PgpHelper; +import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.service.BenchmarkInputParcel; @@ -256,18 +256,18 @@ public class KeyListFragment extends RecyclerFragment> { - private final KeyRingDao keyRingDao; + private final KeyRepository keyRepository; private FlexibleKeyItemFactory flexibleKeyItemFactory; KeyListLiveData(@NonNull Context context) { super(context, KeyRings.CONTENT_URI); - keyRingDao = KeyRingDao.getInstance(context.getApplicationContext()); + keyRepository = KeyRepository.create(context.getApplicationContext()); flexibleKeyItemFactory = new FlexibleKeyItemFactory(context.getResources()); } @Override protected List asyncLoadData() { - List unifiedKeyInfo = keyRingDao.getUnifiedKeyInfo(); + List unifiedKeyInfo = keyRepository.getUnifiedKeyInfo(); return flexibleKeyItemFactory.mapUnifiedKeyInfoToFlexibleKeyItems(unifiedKeyInfo); } } diff --git a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/KeyRingsPublic.sq b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/KeyRingsPublic.sq index 95debd60f..33e3b3f0d 100644 --- a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/KeyRingsPublic.sq +++ b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/KeyRingsPublic.sq @@ -3,6 +3,10 @@ CREATE TABLE IF NOT EXISTS keyrings_public ( key_ring_data BLOB NULL ); +selectAllMasterKeyIds: +SELECT master_key_id + FROM keyrings_public; + selectByMasterKeyId: SELECT * FROM keyrings_public diff --git a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/KeySignatures.sq b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/KeySignatures.sq new file mode 100644 index 000000000..1b61dadf3 --- /dev/null +++ b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/KeySignatures.sq @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS key_signatures ( + master_key_id INTEGER NOT NULL, + signer_key_id INTEGER NOT NULL, + PRIMARY KEY(master_key_id, signer_key_id), + FOREIGN KEY(master_key_id) REFERENCES + keyrings_public(master_key_id) ON DELETE CASCADE +); diff --git a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Keys.sq b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Keys.sq index f69194653..c147c0d1f 100644 --- a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Keys.sq +++ b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Keys.sq @@ -46,4 +46,9 @@ SELECT * selectSecretKeyType: SELECT has_secret FROM keys - WHERE key_id = ?; \ No newline at end of file + WHERE key_id = ?; + +-- TODO move to KeySignatures.sq +selectMasterKeyIdsBySigner: +SELECT master_key_id + FROM key_signatures WHERE signer_key_id IN ?; \ No newline at end of file