move UidStatus querying logic into UserIdDao

This commit is contained in:
Vincent Breitmoser
2018-07-09 14:29:53 +02:00
parent 58e0da0d8c
commit 3150d2d3f9
4 changed files with 78 additions and 77 deletions

View File

@@ -8,6 +8,7 @@ import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.db.SupportSQLiteQuery; import android.arch.persistence.db.SupportSQLiteQuery;
import android.database.Cursor; import android.database.Cursor;
import com.squareup.sqldelight.RowMapper;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
@@ -33,7 +34,7 @@ class AbstractDao {
return databaseNotifyManager; return databaseNotifyManager;
} }
<T> List<T> mapAllRows(SupportSQLiteQuery query, Mapper<T> mapper) { <T> List<T> mapAllRows(SupportSQLiteQuery query, RowMapper<T> mapper) {
ArrayList<T> result = new ArrayList<>(); ArrayList<T> result = new ArrayList<>();
try (Cursor cursor = getReadableDb().query(query)) { try (Cursor cursor = getReadableDb().query(query)) {
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
@@ -44,7 +45,7 @@ class AbstractDao {
return result; return result;
} }
<T> T mapSingleRowOrThrow(SupportSQLiteQuery query, Mapper<T> mapper) throws NotFoundException { <T> T mapSingleRowOrThrow(SupportSQLiteQuery query, RowMapper<T> mapper) throws NotFoundException {
T result = mapSingleRow(query, mapper); T result = mapSingleRow(query, mapper);
if (result == null) { if (result == null) {
throw new NotFoundException(); throw new NotFoundException();
@@ -52,7 +53,7 @@ class AbstractDao {
return result; return result;
} }
<T> T mapSingleRow(SupportSQLiteQuery query, Mapper<T> mapper) { <T> T mapSingleRow(SupportSQLiteQuery query, RowMapper<T> mapper) {
try (Cursor cursor = getReadableDb().query(query)) { try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToNext()) { if (cursor.moveToNext()) {
return mapper.map(cursor); return mapper.map(cursor);
@@ -60,8 +61,4 @@ class AbstractDao {
} }
return null; return null;
} }
interface Mapper<T> {
T map(Cursor cursor);
}
} }

View File

@@ -129,48 +129,48 @@ public class KeyRepository extends AbstractDao {
public List<Long> getAllMasterKeyIds() { public List<Long> getAllMasterKeyIds() {
SqlDelightQuery query = KeyRingPublic.FACTORY.selectAllMasterKeyIds(); SqlDelightQuery query = KeyRingPublic.FACTORY.selectAllMasterKeyIds();
return mapAllRows(query, KeyRingPublic.FACTORY.selectAllMasterKeyIdsMapper()::map); return mapAllRows(query, KeyRingPublic.FACTORY.selectAllMasterKeyIdsMapper());
} }
public List<Long> getMasterKeyIdsBySigner(List<Long> signerMasterKeyIds) { public List<Long> getMasterKeyIdsBySigner(List<Long> signerMasterKeyIds) {
long[] signerKeyIds = getLongListAsArray(signerMasterKeyIds); long[] signerKeyIds = getLongListAsArray(signerMasterKeyIds);
SqlDelightQuery query = KeySignature.FACTORY.selectMasterKeyIdsBySigner(signerKeyIds); SqlDelightQuery query = KeySignature.FACTORY.selectMasterKeyIdsBySigner(signerKeyIds);
return mapAllRows(query, KeySignature.FACTORY.selectMasterKeyIdsBySignerMapper()::map); return mapAllRows(query, KeySignature.FACTORY.selectMasterKeyIdsBySignerMapper());
} }
public Long getMasterKeyIdBySubkeyId(long subKeyId) { public Long getMasterKeyIdBySubkeyId(long subKeyId) {
SqlDelightQuery query = SubKey.FACTORY.selectMasterKeyIdBySubkey(subKeyId); SqlDelightQuery query = SubKey.FACTORY.selectMasterKeyIdBySubkey(subKeyId);
return mapSingleRow(query, SubKey.FACTORY.selectMasterKeyIdBySubkeyMapper()::map); return mapSingleRow(query, SubKey.FACTORY.selectMasterKeyIdBySubkeyMapper());
} }
public UnifiedKeyInfo getUnifiedKeyInfo(long masterKeyId) { public UnifiedKeyInfo getUnifiedKeyInfo(long masterKeyId) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyId(masterKeyId); SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyId(masterKeyId);
return mapSingleRow(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map); return mapSingleRow(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
} }
public List<UnifiedKeyInfo> getUnifiedKeyInfo(long... masterKeyIds) { public List<UnifiedKeyInfo> getUnifiedKeyInfo(long... masterKeyIds) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyIds(masterKeyIds); SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyIds(masterKeyIds);
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map); return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
} }
public List<UnifiedKeyInfo> getUnifiedKeyInfosByMailAddress(String mailAddress) { public List<UnifiedKeyInfo> getUnifiedKeyInfosByMailAddress(String mailAddress) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%'); SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%');
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map); return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
} }
public List<UnifiedKeyInfo> getAllUnifiedKeyInfo() { public List<UnifiedKeyInfo> getAllUnifiedKeyInfo() {
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfo(); SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfo();
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map); return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
} }
public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithSecret() { public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithSecret() {
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfoWithSecret(); SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfoWithSecret();
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER::map); return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
} }
public List<UserId> getUserIds(long... masterKeyIds) { public List<UserId> getUserIds(long... masterKeyIds) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyIds); SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyIds);
return mapAllRows(query, UserPacket.USER_ID_MAPPER::map); return mapAllRows(query, UserPacket.USER_ID_MAPPER);
} }
public List<String> getConfirmedUserIds(long masterKeyId) { public List<String> getConfirmedUserIds(long masterKeyId) {
@@ -181,17 +181,17 @@ public class KeyRepository extends AbstractDao {
public List<SubKey> getSubKeysByMasterKeyId(long masterKeyId) { public List<SubKey> getSubKeysByMasterKeyId(long masterKeyId) {
SqlDelightQuery query = SubKey.FACTORY.selectSubkeysByMasterKeyId(masterKeyId); SqlDelightQuery query = SubKey.FACTORY.selectSubkeysByMasterKeyId(masterKeyId);
return mapAllRows(query, SubKey.SUBKEY_MAPPER::map); return mapAllRows(query, SubKey.SUBKEY_MAPPER);
} }
public SecretKeyType getSecretKeyType(long keyId) throws NotFoundException { public SecretKeyType getSecretKeyType(long keyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectSecretKeyType(keyId); SqlDelightQuery query = SubKey.FACTORY.selectSecretKeyType(keyId);
return mapSingleRowOrThrow(query, SubKey.SKT_MAPPER::map); return mapSingleRowOrThrow(query, SubKey.SKT_MAPPER);
} }
public byte[] getFingerprintByKeyId(long keyId) throws NotFoundException { public byte[] getFingerprintByKeyId(long keyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectFingerprintByKeyId(keyId); SqlDelightQuery query = SubKey.FACTORY.selectFingerprintByKeyId(keyId);
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectFingerprintByKeyIdMapper()::map); return mapSingleRowOrThrow(query, SubKey.FACTORY.selectFingerprintByKeyIdMapper());
} }
private byte[] getKeyRingAsArmoredData(byte[] data) throws IOException { private byte[] getKeyRingAsArmoredData(byte[] data) throws IOException {
@@ -247,12 +247,12 @@ public class KeyRepository extends AbstractDao {
public long getSecretSignId(long masterKeyId) throws NotFoundException { public long getSecretSignId(long masterKeyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyId(masterKeyId); SqlDelightQuery query = SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyId(masterKeyId);
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyIdMapper()::map); return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyIdMapper());
} }
public long getSecretAuthenticationId(long masterKeyId) throws NotFoundException { public long getSecretAuthenticationId(long masterKeyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyId(masterKeyId); SqlDelightQuery query = SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyId(masterKeyId);
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyIdMapper()::map); return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyIdMapper());
} }
public static class NotFoundException extends Exception { public static class NotFoundException extends Exception {

View File

@@ -0,0 +1,26 @@
package org.sufficientlysecure.keychain.daos;
import java.util.List;
import com.squareup.sqldelight.SqlDelightQuery;
import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.model.UserPacket;
import org.sufficientlysecure.keychain.model.UserPacket.UidStatus;
public class UserIdDao extends AbstractDao {
public UserIdDao(KeychainDatabase db, DatabaseNotifyManager databaseNotifyManager) {
super(db, databaseNotifyManager);
}
public List<UidStatus> getUidStatusByEmailLike(String emailLike) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdStatusByEmailLike(emailLike);
return mapAllRows(query, UserPacket.UID_STATUS_MAPPER);
}
public List<UidStatus> getUidStatusByEmail(String... emails) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdStatusByEmail(emails);
return mapAllRows(query, UserPacket.UID_STATUS_MAPPER);
}
}

View File

@@ -36,18 +36,16 @@ import android.net.Uri;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import com.squareup.sqldelight.SqlDelightQuery;
import org.sufficientlysecure.keychain.BuildConfig; import org.sufficientlysecure.keychain.BuildConfig;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.daos.ApiAppDao; import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager; import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
import org.sufficientlysecure.keychain.model.UserPacket; import org.sufficientlysecure.keychain.daos.UserIdDao;
import org.sufficientlysecure.keychain.model.UserPacket.UidStatus; import org.sufficientlysecure.keychain.model.UserPacket.UidStatus;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract; import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptStatus; import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptStatus;
@@ -71,24 +69,12 @@ public class KeychainExternalProvider extends ContentProvider {
private ApiPermissionHelper apiPermissionHelper; private ApiPermissionHelper apiPermissionHelper;
/**
* Build and return a {@link UriMatcher} that catches all {@link Uri} variations supported by
* this {@link ContentProvider}.
*/
protected UriMatcher buildUriMatcher() { protected UriMatcher buildUriMatcher() {
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
String authority = KeychainExternalContract.CONTENT_AUTHORITY_EXTERNAL; String authority = KeychainExternalContract.CONTENT_AUTHORITY_EXTERNAL;
/*
* list email_status
*
* <pre>
* email_status/
* </pre>
*/
matcher.addURI(authority, KeychainExternalContract.BASE_EMAIL_STATUS, EMAIL_STATUS); matcher.addURI(authority, KeychainExternalContract.BASE_EMAIL_STATUS, EMAIL_STATUS);
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS, AUTOCRYPT_STATUS); matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS, AUTOCRYPT_STATUS);
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS + "/*", AUTOCRYPT_STATUS_INTERNAL); matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS + "/*", AUTOCRYPT_STATUS_INTERNAL);
@@ -138,7 +124,8 @@ public class KeychainExternalProvider extends ContentProvider {
String groupBy = null; String groupBy = null;
SupportSQLiteDatabase db = KeychainDatabase.getTemporaryInstance(getContext()).getReadableDatabase(); KeychainDatabase temporaryDb = KeychainDatabase.getTemporaryInstance(getContext());
SupportSQLiteDatabase db = temporaryDb.getReadableDatabase();
String callingPackageName = apiPermissionHelper.getCurrentCallingPackage(); String callingPackageName = apiPermissionHelper.getCurrentCallingPackage();
@@ -243,28 +230,38 @@ public class KeychainExternalProvider extends ContentProvider {
db.insert(TEMP_TABLE_QUERIED_ADDRESSES, SQLiteDatabase.CONFLICT_FAIL, cv); db.insert(TEMP_TABLE_QUERIED_ADDRESSES, SQLiteDatabase.CONFLICT_FAIL, cv);
} }
boolean isWildcardSelector = selectionArgs.length == 1 && selectionArgs[0].contains("%");
List<String> plist = Arrays.asList(projection); List<String> plist = Arrays.asList(projection);
boolean isWildcardSelector = selectionArgs.length == 1 && selectionArgs[0].contains("%");
boolean queriesUidResult = plist.contains(AutocryptStatus.UID_KEY_STATUS) || boolean queriesUidResult = plist.contains(AutocryptStatus.UID_KEY_STATUS) ||
plist.contains(AutocryptStatus.UID_ADDRESS) || plist.contains(AutocryptStatus.UID_ADDRESS) ||
plist.contains(AutocryptStatus.UID_MASTER_KEY_ID) || plist.contains(AutocryptStatus.UID_MASTER_KEY_ID) ||
plist.contains(AutocryptStatus.UID_CANDIDATES); plist.contains(AutocryptStatus.UID_CANDIDATES);
if (queriesUidResult) {
fillTempTableWithUidResult(db, isWildcardSelector, selectionArgs);
}
boolean queriesAutocryptResult = plist.contains(AutocryptStatus.AUTOCRYPT_PEER_STATE) || boolean queriesAutocryptResult = plist.contains(AutocryptStatus.AUTOCRYPT_PEER_STATE) ||
plist.contains(AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID) || plist.contains(AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID) ||
plist.contains(AutocryptStatus.AUTOCRYPT_KEY_STATUS); plist.contains(AutocryptStatus.AUTOCRYPT_KEY_STATUS);
if (isWildcardSelector && queriesAutocryptResult) { if (isWildcardSelector && queriesAutocryptResult) {
throw new UnsupportedOperationException("Cannot wildcard-query autocrypt results!"); throw new UnsupportedOperationException("Cannot wildcard-query autocrypt results!");
} }
if (!isWildcardSelector && queriesAutocryptResult) {
UserIdDao userIdDao = new UserIdDao(temporaryDb, DatabaseNotifyManager.create(getContext()));
if (queriesUidResult) {
List<UidStatus> uidStatuses;
if (isWildcardSelector) {
uidStatuses = userIdDao.getUidStatusByEmailLike(selectionArgs[0]);
} else {
uidStatuses = userIdDao.getUidStatusByEmail(selectionArgs);
}
fillTempTableWithUidResult(db, uidStatuses, isWildcardSelector ? selectionArgs[0] : null);
}
if (queriesAutocryptResult) {
AutocryptInteractor autocryptInteractor = AutocryptInteractor autocryptInteractor =
AutocryptInteractor.getInstance(getContext(), callingPackageName); AutocryptInteractor.getInstance(getContext(), callingPackageName);
fillTempTableWithAutocryptRecommendations(db, autocryptInteractor, selectionArgs); List<AutocryptRecommendationResult> autocryptStates =
autocryptInteractor.determineAutocryptRecommendations(selectionArgs);
fillTempTableWithAutocryptRecommendations(db, autocryptStates);
} }
HashMap<String, String> projectionMap = new HashMap<>(); HashMap<String, String> projectionMap = new HashMap<>();
@@ -320,14 +317,6 @@ public class KeychainExternalProvider extends ContentProvider {
return cursor; return cursor;
} }
private void fillTempTableWithAutocryptRecommendations(SupportSQLiteDatabase db,
AutocryptInteractor autocryptInteractor, String[] peerIds) {
List<AutocryptRecommendationResult> autocryptStates =
autocryptInteractor.determineAutocryptRecommendations(peerIds);
fillTempTableWithAutocryptRecommendations(db, autocryptStates);
}
private void fillTempTableWithAutocryptRecommendations(SupportSQLiteDatabase db, private void fillTempTableWithAutocryptRecommendations(SupportSQLiteDatabase db,
List<AutocryptRecommendationResult> autocryptRecommendations) { List<AutocryptRecommendationResult> autocryptRecommendations) {
ContentValues cv = new ContentValues(); ContentValues cv = new ContentValues();
@@ -347,31 +336,20 @@ public class KeychainExternalProvider extends ContentProvider {
} }
} }
private void fillTempTableWithUidResult(SupportSQLiteDatabase db, private void fillTempTableWithUidResult(SupportSQLiteDatabase db, List<UidStatus> uidStatuses, String key) {
boolean isWildcardSelector, String[] selectionArgs) { ContentValues cv = new ContentValues();
SqlDelightQuery query; for (UidStatus uidStatus : uidStatuses) {
if (isWildcardSelector) { int keyStatus = uidStatus.keyStatus() == VerificationStatus.VERIFIED_SECRET ?
query = UserPacket.FACTORY.selectUserIdStatusByEmailLike(selectionArgs[0]); KeychainExternalContract.KEY_STATUS_VERIFIED : KeychainExternalContract.KEY_STATUS_UNVERIFIED;
} else {
query = UserPacket.FACTORY.selectUserIdStatusByEmail(selectionArgs);
}
try (Cursor cursor = db.query(query)) { cv.put(AutocryptStatus.UID_ADDRESS, uidStatus.user_id());
ContentValues cv = new ContentValues(); cv.put(AutocryptStatus.UID_MASTER_KEY_ID, uidStatus.master_key_id());
while (cursor.moveToNext()) { cv.put(AutocryptStatus.UID_KEY_STATUS, keyStatus);
UidStatus uidStatus = UserPacket.UID_STATUS_MAPPER.map(cursor); cv.put(AutocryptStatus.UID_CANDIDATES, uidStatus.candidates());
int keyStatus = uidStatus.keyStatus() == VerificationStatus.VERIFIED_SECRET ?
KeychainExternalContract.KEY_STATUS_VERIFIED : KeychainExternalContract.KEY_STATUS_UNVERIFIED;
cv.put(AutocryptStatus.UID_ADDRESS, uidStatus.user_id()); db.update(TEMP_TABLE_QUERIED_ADDRESSES, SQLiteDatabase.CONFLICT_IGNORE, cv,
cv.put(AutocryptStatus.UID_MASTER_KEY_ID, uidStatus.master_key_id()); TEMP_TABLE_COLUMN_ADDRES + "= ?",
cv.put(AutocryptStatus.UID_KEY_STATUS, keyStatus); new String[] { key != null ? key : uidStatus.email() });
cv.put(AutocryptStatus.UID_CANDIDATES, uidStatus.candidates());
db.update(TEMP_TABLE_QUERIED_ADDRESSES, SQLiteDatabase.CONFLICT_IGNORE, cv,
TEMP_TABLE_COLUMN_ADDRES + "= ?",
new String[] { isWildcardSelector ? selectionArgs[0] : uidStatus.email() });
}
} }
} }