extract reading of public key data from ContentProvider
This commit is contained in:
parent
6585e7113d
commit
77c89cfa98
|
@ -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<KeyRingPublic> FACTORY = new Factory<>(AutoValue_KeyRingPublic::new);
|
||||
|
||||
public static final Mapper<KeyRingPublic> MAPPER = new Mapper<>(FACTORY);
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
|||
*
|
||||
* <pre>
|
||||
* key_rings/unified
|
||||
* key_rings/public
|
||||
* key_rings/secret
|
||||
* key_rings/user_ids
|
||||
* </pre>
|
||||
*/
|
||||
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/_/_
|
||||
* </pre>
|
||||
*/
|
||||
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<String, String> 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 + ")");
|
||||
}
|
||||
|
|
|
@ -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<ParcelableKeyRing> mKeyList;
|
||||
private HkpKeyserverAddress mKeyserver;
|
||||
private CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult> 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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
CREATE TABLE IF NOT EXISTS keyrings_public (
|
||||
master_key_id INTEGER PRIMARY KEY,
|
||||
key_ring_data BLOB
|
||||
);
|
||||
master_key_id INTEGER NOT NULL PRIMARY KEY,
|
||||
key_ring_data BLOB NULL
|
||||
);
|
||||
|
||||
selectByMasterKeyId:
|
||||
SELECT *
|
||||
FROM keyrings_public
|
||||
WHERE master_key_id = ?;
|
Loading…
Reference in New Issue