diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/KeyRingPublic.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/KeyRingPublic.java new file mode 100644 index 000000000..65a7cf6dd --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/KeyRingPublic.java @@ -0,0 +1,12 @@ +package org.sufficientlysecure.keychain.model; + + +import com.google.auto.value.AutoValue; +import org.sufficientlysecure.keychain.KeyRingsPublicModel; + +@AutoValue +public abstract class KeyRingPublic implements KeyRingsPublicModel { + public static final Factory FACTORY = new Factory<>(AutoValue_KeyRingPublic::new); + + public static final Mapper MAPPER = new Mapper<>(FACTORY); +} 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 5b5f6e82a..5db3f9cd0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyRepository.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyRepository.java @@ -23,12 +23,15 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import android.arch.persistence.db.SupportSQLiteDatabase; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.net.Uri; +import com.squareup.sqldelight.SqlDelightQuery; import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.sufficientlysecure.keychain.model.KeyRingPublic; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; @@ -36,7 +39,6 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; 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.UserPackets; import timber.log.Timber; @@ -54,6 +56,8 @@ public class KeyRepository { final ContentResolver contentResolver; final LocalPublicKeyStorage mLocalPublicKeyStorage; final LocalSecretKeyStorage localSecretKeyStorage; + final SupportSQLiteDatabase db; + OperationLog mLog; int mIndent; @@ -61,18 +65,23 @@ public class KeyRepository { ContentResolver contentResolver = context.getContentResolver(); LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context); LocalSecretKeyStorage localSecretKeyStorage = LocalSecretKeyStorage.getInstance(context); + SupportSQLiteDatabase db = new KeychainDatabase(context).getWritableDatabase(); - return new KeyRepository(contentResolver, localPublicKeyStorage, localSecretKeyStorage); + return new KeyRepository(contentResolver, db, localPublicKeyStorage, localSecretKeyStorage); } - private KeyRepository(ContentResolver contentResolver, LocalPublicKeyStorage localPublicKeyStorage, + private KeyRepository(ContentResolver contentResolver, SupportSQLiteDatabase db, + LocalPublicKeyStorage localPublicKeyStorage, LocalSecretKeyStorage localSecretKeyStorage) { - this(contentResolver, localPublicKeyStorage, localSecretKeyStorage, new OperationLog(), 0); + this(contentResolver, db, localPublicKeyStorage, localSecretKeyStorage, new OperationLog(), 0); } - KeyRepository(ContentResolver contentResolver, LocalPublicKeyStorage localPublicKeyStorage, - LocalSecretKeyStorage localSecretKeyStorage, OperationLog log, int indent) { + KeyRepository(ContentResolver contentResolver, SupportSQLiteDatabase db, + LocalPublicKeyStorage localPublicKeyStorage, + LocalSecretKeyStorage localSecretKeyStorage, + OperationLog log, int indent) { this.contentResolver = contentResolver; + this.db = db; mLocalPublicKeyStorage = localPublicKeyStorage; this.localSecretKeyStorage = localSecretKeyStorage; mIndent = indent; @@ -107,10 +116,6 @@ public class KeyRepository { return result; } - Object getGenericDataOrNull(Uri uri, String column, int type) throws NotFoundException { - return getGenericData(uri, new String[]{column}, new int[]{type}, null).get(column); - } - Object getGenericData(Uri uri, String column, int type, String selection) throws NotFoundException { return getGenericData(uri, new String[]{column}, new int[]{type}, selection).get(column); @@ -282,23 +287,20 @@ public class KeyRepository { } public final byte[] loadPublicKeyRingData(long masterKeyId) throws NotFoundException { - byte[] data = (byte[]) getGenericDataOrNull(KeyRingData.buildPublicKeyRingUri(masterKeyId), - KeyRingData.KEY_RING_DATA, FIELD_TYPE_BLOB); - - if (data == null) { - try { - data = mLocalPublicKeyStorage.readPublicKey(masterKeyId); - } catch (IOException e) { - Timber.e(e, "Error reading public key from storage!"); - throw new NotFoundException(); + SqlDelightQuery query = KeyRingPublic.FACTORY.selectByMasterKeyId(masterKeyId); + try (Cursor cursor = db.query(query)) { + if (cursor.moveToFirst()) { + KeyRingPublic keyRingPublic = KeyRingPublic.MAPPER.map(cursor); + byte[] keyRingData = keyRingPublic.key_ring_data(); + if (keyRingData == null) { + keyRingData = mLocalPublicKeyStorage.readPublicKey(masterKeyId); + } + return keyRingData; } + } catch (IOException e) { + Timber.e(e, "Error reading public key from storage!"); } - - if (data == null) { - throw new NotFoundException(); - } - - return data; + throw new NotFoundException(); } public final byte[] loadSecretKeyRingData(long masterKeyId) throws NotFoundException { 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 a4eed8d49..f860a53a1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyWritableRepository.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeyWritableRepository.java @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.Date; import java.util.List; +import android.arch.persistence.db.SupportSQLiteDatabase; import android.content.ContentProviderOperation; import android.content.ContentValues; import android.content.Context; @@ -90,23 +91,25 @@ public class KeyWritableRepository extends KeyRepository { LocalSecretKeyStorage localSecretKeyStorage = LocalSecretKeyStorage.getInstance(context); DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context); AutocryptPeerDao autocryptPeerDao = AutocryptPeerDao.getInstance(context); - return new KeyWritableRepository(context, localPublicKeyStorage, localSecretKeyStorage, databaseNotifyManager, - autocryptPeerDao); + SupportSQLiteDatabase db = new KeychainDatabase(context).getWritableDatabase(); + return new KeyWritableRepository(context, db, + localPublicKeyStorage, localSecretKeyStorage, databaseNotifyManager, autocryptPeerDao); } @VisibleForTesting KeyWritableRepository(Context context, - LocalPublicKeyStorage localPublicKeyStorage, + SupportSQLiteDatabase db, LocalPublicKeyStorage localPublicKeyStorage, LocalSecretKeyStorage localSecretKeyStorage, DatabaseNotifyManager databaseNotifyManager, AutocryptPeerDao autocryptPeerDao) { - this(context, localPublicKeyStorage, localSecretKeyStorage, databaseNotifyManager, new OperationLog(), 0, + this(context, db, localPublicKeyStorage, localSecretKeyStorage, databaseNotifyManager, new OperationLog(), 0, autocryptPeerDao); } - private KeyWritableRepository(Context context, LocalPublicKeyStorage localPublicKeyStorage, + private KeyWritableRepository(Context context, SupportSQLiteDatabase db, + LocalPublicKeyStorage localPublicKeyStorage, LocalSecretKeyStorage localSecretKeyStorage, DatabaseNotifyManager databaseNotifyManager, OperationLog log, int indent, AutocryptPeerDao autocryptPeerDao) { - super(context.getContentResolver(), localPublicKeyStorage, localSecretKeyStorage, log, indent); + super(context.getContentResolver(), db, localPublicKeyStorage, localSecretKeyStorage, log, indent); this.context = context; this.databaseNotifyManager = databaseNotifyManager; 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 19641d835..85e79df25 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -186,22 +186,9 @@ public class KeychainContract { public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() .appendPath(BASE_KEY_RINGS).build(); - public static final String CONTENT_TYPE - = "vnd.android.cursor.dir/vnd.org.sufficientlysecure.keychain.provider.key_ring_data"; - public static final String CONTENT_ITEM_TYPE - = "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.provider.key_ring_data"; - - public static Uri buildPublicKeyRingUri() { - return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).build(); - } - public static Uri buildPublicKeyRingUri(long masterKeyId) { return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).appendPath(PATH_PUBLIC).build(); } - - public static Uri buildPublicKeyRingUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_PUBLIC).build(); - } } public static class Keys implements KeysColumns, BaseColumns { 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 f3b38f8b1..708bfd649 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -57,7 +57,6 @@ import static android.database.DatabaseUtils.dumpCursorToString; public class KeychainProvider extends ContentProvider implements SimpleContentResolverInterface { private static final int KEY_RINGS_UNIFIED = 101; - private static final int KEY_RINGS_PUBLIC = 102; private static final int KEY_RINGS_USER_IDS = 104; private static final int KEY_RING_UNIFIED = 200; @@ -90,17 +89,12 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe * *
          * key_rings/unified
-         * key_rings/public
-         * key_rings/secret
          * key_rings/user_ids
          * 
*/ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_UNIFIED, KEY_RINGS_UNIFIED); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS - + "/" + KeychainContract.PATH_PUBLIC, - KEY_RINGS_PUBLIC); matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_USER_IDS, KEY_RINGS_USER_IDS); @@ -133,12 +127,8 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe * key_rings/_/keys * key_rings/_/user_ids * key_rings/_/linked_ids - * key_rings/_/linked_ids/_ - * key_rings/_/linked_ids/_/certs * key_rings/_/public - * key_rings/_/secret * key_rings/_/certs - * key_rings/_/certs/_/_ * */ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" @@ -190,9 +180,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe public String getType(@NonNull Uri uri) { final int match = mUriMatcher.match(uri); switch (match) { - case KEY_RING_PUBLIC: - return KeyRings.CONTENT_ITEM_TYPE; - case KEY_RING_KEYS: return Keys.CONTENT_TYPE; @@ -537,24 +524,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe break; } - case KEY_RINGS_PUBLIC: - case KEY_RING_PUBLIC: { - HashMap projectionMap = new HashMap<>(); - projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_PUBLIC + ".oid AS _id"); - projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID); - projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA); - qb.setProjectionMap(projectionMap); - - qb.setTables(Tables.KEY_RINGS_PUBLIC); - - if(match == KEY_RING_PUBLIC) { - qb.appendWhere(KeyRings.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - } - - break; - } - default: { throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")"); } 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 5da61584f..c9c8c80a5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import android.annotation.TargetApi; import android.content.Intent; import android.graphics.PorterDuff; -import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.view.View; @@ -40,9 +39,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.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeyRepository; -import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; @@ -67,12 +65,14 @@ public class SafeSlingerActivity extends BaseActivity private ArrayList mKeyList; private HkpKeyserverAddress mKeyserver; private CryptoOperationHelper mOperationHelper; + private KeyRepository keyRepository; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + keyRepository = KeyRepository.create(this); mMasterKeyId = getIntent().getLongExtra(EXTRA_MASTER_KEY_ID, 0); NumberPicker picker = findViewById(R.id.safe_slinger_picker); @@ -104,10 +104,8 @@ public class SafeSlingerActivity extends BaseActivity } private void startExchange(long masterKeyId, int number) { - // retrieve public key blob and start SafeSlinger - Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(masterKeyId); try { - byte[] keyBlob = KeyRepository.create(this).getCachedPublicKeyRing(uri).getEncoded(); + byte[] keyBlob = keyRepository.loadPublicKeyRingData(masterKeyId); Intent slingerIntent = new Intent(this, ExchangeActivity.class); @@ -115,8 +113,8 @@ 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 (PgpKeyNotFoundException e) { - Timber.e(e, "personal key not found"); + } catch (NotFoundException e) { + Timber.e(e, "key for transfer not found"); } } diff --git a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/KeyRingsPublic.sq b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/KeyRingsPublic.sq index be8435d7b..67c48f36f 100644 --- a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/KeyRingsPublic.sq +++ b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/KeyRingsPublic.sq @@ -1,4 +1,9 @@ CREATE TABLE IF NOT EXISTS keyrings_public ( - master_key_id INTEGER PRIMARY KEY, - key_ring_data BLOB -); \ No newline at end of file + master_key_id INTEGER NOT NULL PRIMARY KEY, + key_ring_data BLOB NULL +); + +selectByMasterKeyId: +SELECT * + FROM keyrings_public + WHERE master_key_id = ?; \ No newline at end of file