introduce AbstractDao, fix import of keys (missing delete in KeychainProvider)

This commit is contained in:
Vincent Breitmoser
2018-06-22 10:53:04 +02:00
parent 587b8b4cc9
commit 1556db897f
21 changed files with 166 additions and 144 deletions

View File

@@ -0,0 +1,27 @@
package org.sufficientlysecure.keychain.provider;
import android.arch.persistence.db.SupportSQLiteDatabase;
class AbstractDao {
private final KeychainDatabase db;
private final DatabaseNotifyManager databaseNotifyManager;
AbstractDao(KeychainDatabase db, DatabaseNotifyManager databaseNotifyManager) {
this.db = db;
this.databaseNotifyManager = databaseNotifyManager;
}
SupportSQLiteDatabase getReadableDb() {
return db.getReadableDatabase();
}
SupportSQLiteDatabase getWritableDb() {
return db.getWritableDatabase();
}
DatabaseNotifyManager getDatabaseNotifyManager() {
return databaseNotifyManager;
}
}

View File

@@ -23,7 +23,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.content.Context;
import android.database.Cursor;
@@ -36,16 +35,20 @@ import org.sufficientlysecure.keychain.model.ApiAllowedKey;
import org.sufficientlysecure.keychain.model.ApiApp;
public class ApiDataAccessObject {
private final SupportSQLiteDatabase db;
public ApiDataAccessObject(Context context) {
public class ApiAppDao extends AbstractDao {
public static ApiAppDao getInstance(Context context) {
KeychainDatabase keychainDatabase = new KeychainDatabase(context);
db = keychainDatabase.getWritableDatabase();
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
return new ApiAppDao(keychainDatabase, databaseNotifyManager);
}
private ApiAppDao(KeychainDatabase keychainDatabase, DatabaseNotifyManager databaseNotifyManager) {
super(keychainDatabase, databaseNotifyManager);
}
public ApiApp getApiApp(String packageName) {
try (Cursor cursor = db.query(ApiApp.FACTORY.selectByPackageName(packageName))) {
try (Cursor cursor = getReadableDb().query(ApiApp.FACTORY.selectByPackageName(packageName))) {
if (cursor.moveToFirst()) {
return ApiApp.FACTORY.selectByPackageNameMapper().map(cursor);
}
@@ -54,7 +57,7 @@ public class ApiDataAccessObject {
}
public byte[] getApiAppCertificate(String packageName) {
try (Cursor cursor = db.query(ApiApp.FACTORY.getCertificate(packageName))) {
try (Cursor cursor = getReadableDb().query(ApiApp.FACTORY.getCertificate(packageName))) {
if (cursor.moveToFirst()) {
return ApiApp.FACTORY.getCertificateMapper().map(cursor);
}
@@ -63,13 +66,13 @@ public class ApiDataAccessObject {
}
public void insertApiApp(ApiApp apiApp) {
InsertApiApp statement = new ApiAppsModel.InsertApiApp(db);
InsertApiApp statement = new ApiAppsModel.InsertApiApp(getWritableDb());
statement.bind(apiApp.package_name(), apiApp.package_signature());
statement.execute();
}
public void deleteApiApp(String packageName) {
DeleteByPackageName deleteByPackageName = new DeleteByPackageName(db);
DeleteByPackageName deleteByPackageName = new DeleteByPackageName(getWritableDb());
deleteByPackageName.bind(packageName);
deleteByPackageName.executeUpdateDelete();
}
@@ -77,7 +80,7 @@ public class ApiDataAccessObject {
public HashSet<Long> getAllowedKeyIdsForApp(String packageName) {
SqlDelightQuery allowedKeys = ApiAllowedKey.FACTORY.getAllowedKeys(packageName);
HashSet<Long> keyIds = new HashSet<>();
try (Cursor cursor = db.query(allowedKeys)) {
try (Cursor cursor = getReadableDb().query(allowedKeys)) {
while (cursor.moveToNext()) {
long allowedKeyId = ApiAllowedKey.FACTORY.getAllowedKeysMapper().map(cursor);
keyIds.add(allowedKeyId);
@@ -87,11 +90,11 @@ public class ApiDataAccessObject {
}
public void saveAllowedKeyIdsForApp(String packageName, Set<Long> allowedKeyIds) {
ApiAllowedKey.DeleteByPackageName deleteByPackageName = new ApiAllowedKey.DeleteByPackageName(db);
ApiAllowedKey.DeleteByPackageName deleteByPackageName = new ApiAllowedKey.DeleteByPackageName(getWritableDb());
deleteByPackageName.bind(packageName);
deleteByPackageName.executeUpdateDelete();
InsertAllowedKey statement = new InsertAllowedKey(db);
InsertAllowedKey statement = new InsertAllowedKey(getWritableDb());
for (Long keyId : allowedKeyIds) {
statement.bind(packageName, keyId);
statement.execute();
@@ -99,7 +102,7 @@ public class ApiDataAccessObject {
}
public void addAllowedKeyIdForApp(String packageName, long allowedKeyId) {
InsertAllowedKey statement = new InsertAllowedKey(db);
InsertAllowedKey statement = new InsertAllowedKey(getWritableDb());
statement.bind(packageName, allowedKeyId);
statement.execute();
}
@@ -108,7 +111,7 @@ public class ApiDataAccessObject {
SqlDelightQuery query = ApiApp.FACTORY.selectAll();
ArrayList<ApiApp> result = new ArrayList<>();
try (Cursor cursor = db.query(query)) {
try (Cursor cursor = getReadableDb().query(query)) {
while (cursor.moveToNext()) {
ApiApp apiApp = ApiApp.FACTORY.selectAllMapper().map(cursor);
result.add(apiApp);

View File

@@ -22,7 +22,6 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.content.Context;
import android.database.Cursor;
import android.support.annotation.Nullable;
@@ -39,25 +38,21 @@ import org.sufficientlysecure.keychain.model.AutocryptPeer.AutocryptKeyStatus;
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
public class AutocryptPeerDao {
private final SupportSQLiteDatabase db;
private final DatabaseNotifyManager databaseNotifyManager;
public class AutocryptPeerDao extends AbstractDao {
public static AutocryptPeerDao getInstance(Context context) {
KeychainDatabase keychainDatabase = new KeychainDatabase(context);
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
return new AutocryptPeerDao(keychainDatabase.getWritableDatabase(), databaseNotifyManager);
return new AutocryptPeerDao(keychainDatabase, databaseNotifyManager);
}
private AutocryptPeerDao(SupportSQLiteDatabase writableDatabase, DatabaseNotifyManager databaseNotifyManager) {
this.db = writableDatabase;
this.databaseNotifyManager = databaseNotifyManager;
private AutocryptPeerDao(KeychainDatabase database, DatabaseNotifyManager databaseNotifyManager) {
super(database, databaseNotifyManager);
}
public Long getMasterKeyIdForAutocryptPeer(String autocryptId) {
SqlDelightQuery query = AutocryptPeer.FACTORY.selectMasterKeyIdByIdentifier(autocryptId);
try (Cursor cursor = db.query(query)) {
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToFirst()) {
return AutocryptPeer.FACTORY.selectMasterKeyIdByIdentifierMapper().map(cursor);
}
@@ -74,10 +69,10 @@ public class AutocryptPeerDao {
return null;
}
public List<AutocryptPeer> getAutocryptPeers(String packageName, String... autocryptId) {
private List<AutocryptPeer> getAutocryptPeers(String packageName, String... autocryptId) {
ArrayList<AutocryptPeer> result = new ArrayList<>(autocryptId.length);
SqlDelightQuery query = AutocryptPeer.FACTORY.selectByIdentifiers(packageName, autocryptId);
try (Cursor cursor = db.query(query)) {
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToNext()) {
AutocryptPeer autocryptPeer = AutocryptPeer.PEER_MAPPER.map(cursor);
result.add(autocryptPeer);
@@ -89,7 +84,7 @@ public class AutocryptPeerDao {
public List<AutocryptKeyStatus> getAutocryptKeyStatus(String packageName, String[] autocryptIds) {
ArrayList<AutocryptKeyStatus> result = new ArrayList<>(autocryptIds.length);
SqlDelightQuery query = AutocryptPeer.FACTORY.selectAutocryptKeyStatus(packageName, autocryptIds, System.currentTimeMillis());
try (Cursor cursor = db.query(query)) {
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToNext()) {
AutocryptKeyStatus autocryptPeer = AutocryptPeer.KEY_STATUS_MAPPER.map(cursor);
result.add(autocryptPeer);
@@ -99,12 +94,12 @@ public class AutocryptPeerDao {
}
public void insertOrUpdateLastSeen(String packageName, String autocryptId, Date date) {
UpdateLastSeen updateStatement = new UpdateLastSeen(db, AutocryptPeer.FACTORY);
UpdateLastSeen updateStatement = new UpdateLastSeen(getWritableDb(), AutocryptPeer.FACTORY);
updateStatement.bind(packageName, autocryptId, date);
int updated = updateStatement.executeUpdateDelete();
if (updated == 0) {
InsertPeer insertStatement = new InsertPeer(db, AutocryptPeer.FACTORY);
InsertPeer insertStatement = new InsertPeer(getWritableDb(), AutocryptPeer.FACTORY);
insertStatement.bind(packageName, autocryptId, date);
insertStatement.executeInsert();
}
@@ -112,30 +107,30 @@ public class AutocryptPeerDao {
public void updateKey(String packageName, String autocryptId, Date effectiveDate, long masterKeyId,
boolean isMutual) {
UpdateKey updateStatement = new UpdateKey(db, AutocryptPeer.FACTORY);
UpdateKey updateStatement = new UpdateKey(getWritableDb(), AutocryptPeer.FACTORY);
updateStatement.bind(packageName, autocryptId, effectiveDate, masterKeyId, isMutual);
int rowsUpdated = updateStatement.executeUpdateDelete();
if (rowsUpdated == 0) {
throw new IllegalStateException("No rows updated! Was this peer inserted before the update?");
}
databaseNotifyManager.notifyAutocryptUpdate(autocryptId, masterKeyId);
getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId);
}
public void updateKeyGossip(String packageName, String autocryptId, Date effectiveDate, long masterKeyId,
GossipOrigin origin) {
UpdateGossipKey updateStatement = new UpdateGossipKey(db, AutocryptPeer.FACTORY);
UpdateGossipKey updateStatement = new UpdateGossipKey(getWritableDb(), AutocryptPeer.FACTORY);
updateStatement.bind(packageName, autocryptId, effectiveDate, masterKeyId, origin);
int rowsUpdated = updateStatement.executeUpdateDelete();
if (rowsUpdated == 0) {
throw new IllegalStateException("No rows updated! Was this peer inserted before the update?");
}
databaseNotifyManager.notifyAutocryptUpdate(autocryptId, masterKeyId);
getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId);
}
public List<AutocryptPeer> getAutocryptPeersForKey(long masterKeyId) {
ArrayList<AutocryptPeer> result = new ArrayList<>();
SqlDelightQuery query = AutocryptPeer.FACTORY.selectByMasterKeyId(masterKeyId);
try (Cursor cursor = db.query(query)) {
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToNext()) {
AutocryptPeer autocryptPeer = AutocryptPeer.PEER_MAPPER.map(cursor);
result.add(autocryptPeer);
@@ -146,16 +141,16 @@ public class AutocryptPeerDao {
public void deleteByIdentifier(String packageName, String autocryptId) {
Long masterKeyId = getMasterKeyIdForAutocryptPeer(autocryptId);
DeleteByIdentifier deleteStatement = new DeleteByIdentifier(db);
DeleteByIdentifier deleteStatement = new DeleteByIdentifier(getReadableDb());
deleteStatement.bind(packageName, autocryptId);
deleteStatement.execute();
if (masterKeyId != null) {
databaseNotifyManager.notifyAutocryptDelete(autocryptId, masterKeyId);
getDatabaseNotifyManager().notifyAutocryptDelete(autocryptId, masterKeyId);
}
}
public void deleteByMasterKeyId(long masterKeyId) {
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(db);
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(getReadableDb());
deleteStatement.bind(masterKeyId);
deleteStatement.execute();
}

View File

@@ -6,7 +6,6 @@ import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.content.Context;
import android.database.Cursor;
@@ -15,26 +14,21 @@ import org.sufficientlysecure.keychain.KeyMetadataModel.ReplaceKeyMetadata;
import org.sufficientlysecure.keychain.model.KeyMetadata;
public class KeyMetadataDao {
private final SupportSQLiteDatabase db;
private DatabaseNotifyManager databaseNotifyManager;
public class KeyMetadataDao extends AbstractDao {
public static KeyMetadataDao create(Context context) {
SupportSQLiteDatabase supportSQLiteDatabase = new KeychainDatabase(context).getWritableDatabase();
KeychainDatabase database = new KeychainDatabase(context);
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
return new KeyMetadataDao(supportSQLiteDatabase, databaseNotifyManager);
return new KeyMetadataDao(database, databaseNotifyManager);
}
private KeyMetadataDao(SupportSQLiteDatabase supportSQLiteDatabase, DatabaseNotifyManager databaseNotifyManager) {
this.db = supportSQLiteDatabase;
this.databaseNotifyManager = databaseNotifyManager;
private KeyMetadataDao(KeychainDatabase database, DatabaseNotifyManager databaseNotifyManager) {
super(database, databaseNotifyManager);
}
public KeyMetadata getKeyMetadata(long masterKeyId) {
SqlDelightQuery query = KeyMetadata.FACTORY.selectByMasterKeyId(masterKeyId);
try (Cursor cursor = db.query(query)) {
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToFirst()) {
return KeyMetadata.FACTORY.selectByMasterKeyIdMapper().map(cursor);
}
@@ -43,22 +37,22 @@ public class KeyMetadataDao {
}
public void resetAllLastUpdatedTimes() {
new KeyMetadata.DeleteAllLastUpdatedTimes(db).execute();
new KeyMetadata.DeleteAllLastUpdatedTimes(getWritableDb()).execute();
}
public void renewKeyLastUpdatedTime(long masterKeyId, boolean seenOnKeyservers) {
ReplaceKeyMetadata replaceStatement = new ReplaceKeyMetadata(db, KeyMetadata.FACTORY);
ReplaceKeyMetadata replaceStatement = new ReplaceKeyMetadata(getWritableDb(), KeyMetadata.FACTORY);
replaceStatement.bind(masterKeyId, new Date(), seenOnKeyservers);
replaceStatement.executeInsert();
databaseNotifyManager.notifyKeyMetadataChange(masterKeyId);
getDatabaseNotifyManager().notifyKeyMetadataChange(masterKeyId);
}
public List<byte[]> getFingerprintsForKeysOlderThan(long olderThan, TimeUnit timeUnit) {
SqlDelightQuery query = KeyMetadata.FACTORY.selectFingerprintsForKeysOlderThan(new Date(timeUnit.toMillis(olderThan)));
List<byte[]> fingerprintList = new ArrayList<>();
try (Cursor cursor = db.query(query)) {
try (Cursor cursor = getReadableDb().query(query)) {
while (cursor.moveToNext()) {
byte[] fingerprint = KeyMetadata.FACTORY.selectFingerprintsForKeysOlderThanMapper().map(cursor);
fingerprintList.add(fingerprint);

View File

@@ -23,7 +23,6 @@ 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;
@@ -44,7 +43,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
import timber.log.Timber;
public class KeyRepository {
public class KeyRepository extends AbstractDao {
// 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)
@@ -56,7 +55,6 @@ public class KeyRepository {
final ContentResolver contentResolver;
final LocalPublicKeyStorage mLocalPublicKeyStorage;
final LocalSecretKeyStorage localSecretKeyStorage;
final SupportSQLiteDatabase db;
OperationLog mLog;
int mIndent;
@@ -65,23 +63,26 @@ public class KeyRepository {
ContentResolver contentResolver = context.getContentResolver();
LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context);
LocalSecretKeyStorage localSecretKeyStorage = LocalSecretKeyStorage.getInstance(context);
SupportSQLiteDatabase db = new KeychainDatabase(context).getWritableDatabase();
KeychainDatabase database = new KeychainDatabase(context);
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
return new KeyRepository(contentResolver, db, localPublicKeyStorage, localSecretKeyStorage);
return new KeyRepository(contentResolver, database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage);
}
private KeyRepository(ContentResolver contentResolver, SupportSQLiteDatabase db,
private KeyRepository(ContentResolver contentResolver, KeychainDatabase database,
DatabaseNotifyManager databaseNotifyManager,
LocalPublicKeyStorage localPublicKeyStorage,
LocalSecretKeyStorage localSecretKeyStorage) {
this(contentResolver, db, localPublicKeyStorage, localSecretKeyStorage, new OperationLog(), 0);
this(contentResolver, database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage, new OperationLog(), 0);
}
KeyRepository(ContentResolver contentResolver, SupportSQLiteDatabase db,
KeyRepository(ContentResolver contentResolver, KeychainDatabase database,
DatabaseNotifyManager databaseNotifyManager,
LocalPublicKeyStorage localPublicKeyStorage,
LocalSecretKeyStorage localSecretKeyStorage,
OperationLog log, int indent) {
super(database, databaseNotifyManager);
this.contentResolver = contentResolver;
this.db = db;
mLocalPublicKeyStorage = localPublicKeyStorage;
this.localSecretKeyStorage = localSecretKeyStorage;
mIndent = indent;
@@ -288,7 +289,7 @@ public class KeyRepository {
public final byte[] loadPublicKeyRingData(long masterKeyId) throws NotFoundException {
SqlDelightQuery query = KeyRingPublic.FACTORY.selectByMasterKeyId(masterKeyId);
try (Cursor cursor = db.query(query)) {
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToFirst()) {
KeyRingPublic keyRingPublic = KeyRingPublic.MAPPER.map(cursor);
byte[] keyRingData = keyRingPublic.key_ring_data();

View File

@@ -25,7 +25,6 @@ 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;
@@ -92,25 +91,26 @@ public class KeyWritableRepository extends KeyRepository {
LocalSecretKeyStorage localSecretKeyStorage = LocalSecretKeyStorage.getInstance(context);
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
AutocryptPeerDao autocryptPeerDao = AutocryptPeerDao.getInstance(context);
SupportSQLiteDatabase db = new KeychainDatabase(context).getWritableDatabase();
return new KeyWritableRepository(context, db,
KeychainDatabase database = new KeychainDatabase(context);
return new KeyWritableRepository(context, database,
localPublicKeyStorage, localSecretKeyStorage, databaseNotifyManager, autocryptPeerDao);
}
@VisibleForTesting
KeyWritableRepository(Context context,
SupportSQLiteDatabase db, LocalPublicKeyStorage localPublicKeyStorage,
KeychainDatabase database, LocalPublicKeyStorage localPublicKeyStorage,
LocalSecretKeyStorage localSecretKeyStorage,
DatabaseNotifyManager databaseNotifyManager, AutocryptPeerDao autocryptPeerDao) {
this(context, db, localPublicKeyStorage, localSecretKeyStorage, databaseNotifyManager, new OperationLog(), 0,
this(context, database, localPublicKeyStorage, localSecretKeyStorage, databaseNotifyManager, new OperationLog(), 0,
autocryptPeerDao);
}
private KeyWritableRepository(Context context, SupportSQLiteDatabase db,
private KeyWritableRepository(Context context, KeychainDatabase database,
LocalPublicKeyStorage localPublicKeyStorage,
LocalSecretKeyStorage localSecretKeyStorage, DatabaseNotifyManager databaseNotifyManager,
OperationLog log, int indent, AutocryptPeerDao autocryptPeerDao) {
super(context.getContentResolver(), db, localPublicKeyStorage, localSecretKeyStorage, log, indent);
super(context.getContentResolver(), database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage, log, indent);
this.context = context;
this.databaseNotifyManager = databaseNotifyManager;
@@ -535,9 +535,11 @@ public class KeyWritableRepository extends KeyRepository {
try {
// delete old version of this keyRing (from database only!), which also deletes all keys and userIds on cascade
int deleted = contentResolver.delete(
KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null);
if (deleted > 0) {
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(getWritableDb());
deleteStatement.bind(masterKeyId);
int deletedRows = deleteStatement.executeUpdateDelete();
if (deletedRows > 0) {
log(LogType.MSG_IP_DELETE_OLD_OK);
result |= SaveKeyringResult.UPDATED;
} else {
@@ -595,7 +597,7 @@ public class KeyWritableRepository extends KeyRepository {
}
autocryptPeerDao.deleteByMasterKeyId(masterKeyId);
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(db);
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(getWritableDb());
deleteStatement.bind(masterKeyId);
int deletedRows = deleteStatement.executeUpdateDelete();

View File

@@ -26,7 +26,7 @@ import android.net.Uri;
* from {#android.content.ContentResolver}. It is used to allow substitution
* of a ContentResolver in DAOs.
*
* @see ApiDataAccessObject
* @see ApiAppDao
*/
public interface SimpleContentResolverInterface {
Cursor query(Uri contentUri, String[] projection, String selection, String[] selectionArgs, String sortOrder);