Introduce uidStatus view for external provider
This commit is contained in:
@@ -51,7 +51,7 @@ import timber.log.Timber;
|
|||||||
*/
|
*/
|
||||||
public class KeychainDatabase {
|
public class KeychainDatabase {
|
||||||
private static final String DATABASE_NAME = "openkeychain.db";
|
private static final String DATABASE_NAME = "openkeychain.db";
|
||||||
private static final int DATABASE_VERSION = 29;
|
private static final int DATABASE_VERSION = 30;
|
||||||
private final SupportSQLiteOpenHelper supportSQLiteOpenHelper;
|
private final SupportSQLiteOpenHelper supportSQLiteOpenHelper;
|
||||||
|
|
||||||
private static KeychainDatabase sInstance;
|
private static KeychainDatabase sInstance;
|
||||||
@@ -133,6 +133,8 @@ public class KeychainDatabase {
|
|||||||
db.execSQL(AutocryptPeersModel.CREATE_TABLE);
|
db.execSQL(AutocryptPeersModel.CREATE_TABLE);
|
||||||
db.execSQL(ApiAllowedKeysModel.CREATE_TABLE);
|
db.execSQL(ApiAllowedKeysModel.CREATE_TABLE);
|
||||||
db.execSQL(KeysModel.UNIFIEDKEYVIEW);
|
db.execSQL(KeysModel.UNIFIEDKEYVIEW);
|
||||||
|
db.execSQL(KeysModel.VALIDKEYSVIEW);
|
||||||
|
db.execSQL(UserPacketsModel.UIDSTATUS);
|
||||||
|
|
||||||
db.execSQL("CREATE INDEX keys_by_rank ON keys (" + KeysColumns.RANK + ", " + KeysColumns.MASTER_KEY_ID + ");");
|
db.execSQL("CREATE INDEX keys_by_rank ON keys (" + KeysColumns.RANK + ", " + KeysColumns.MASTER_KEY_ID + ");");
|
||||||
db.execSQL("CREATE INDEX uids_by_rank ON user_packets (" + UserPacketsColumns.RANK + ", "
|
db.execSQL("CREATE INDEX uids_by_rank ON user_packets (" + UserPacketsColumns.RANK + ", "
|
||||||
@@ -356,18 +358,28 @@ public class KeychainDatabase {
|
|||||||
renameApiAutocryptPeersTable(db);
|
renameApiAutocryptPeersTable(db);
|
||||||
|
|
||||||
case 28:
|
case 28:
|
||||||
recreateUnifiedKeyView(db);
|
|
||||||
// drop old table from version 20
|
// drop old table from version 20
|
||||||
db.execSQL("DROP TABLE IF EXISTS api_accounts");
|
db.execSQL("DROP TABLE IF EXISTS api_accounts");
|
||||||
|
|
||||||
|
case 29:
|
||||||
|
recreateUnifiedKeyView(db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void recreateUnifiedKeyView(SupportSQLiteDatabase db) {
|
private void recreateUnifiedKeyView(SupportSQLiteDatabase db) {
|
||||||
try {
|
try {
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
|
|
||||||
// noinspection deprecation
|
// noinspection deprecation
|
||||||
db.execSQL("DROP VIEW IF EXISTS " + KeysModel.UNIFIEDKEYVIEW_VIEW_NAME);
|
db.execSQL("DROP VIEW IF EXISTS " + KeysModel.UNIFIEDKEYVIEW_VIEW_NAME);
|
||||||
db.execSQL(KeysModel.UNIFIEDKEYVIEW);
|
db.execSQL(KeysModel.UNIFIEDKEYVIEW);
|
||||||
|
// noinspection deprecation
|
||||||
|
db.execSQL("DROP VIEW IF EXISTS " + KeysModel.VALIDMASTERKEYS_VIEW_NAME);
|
||||||
|
db.execSQL(KeysModel.VALIDKEYSVIEW);
|
||||||
|
// noinspection deprecation
|
||||||
|
db.execSQL("DROP VIEW IF EXISTS " + UserPacketsModel.UIDSTATUS_VIEW_NAME);
|
||||||
|
db.execSQL(UserPacketsModel.UIDSTATUS);
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ public abstract class UserPacket implements UserPacketsModel {
|
|||||||
FACTORY.selectUserIdsByMasterKeyIdMapper(AutoValue_UserPacket_UserId::new);
|
FACTORY.selectUserIdsByMasterKeyIdMapper(AutoValue_UserPacket_UserId::new);
|
||||||
public static final SelectUserAttributesByTypeAndMasterKeyIdMapper<UserAttribute> USER_ATTRIBUTE_MAPPER =
|
public static final SelectUserAttributesByTypeAndMasterKeyIdMapper<UserAttribute> USER_ATTRIBUTE_MAPPER =
|
||||||
FACTORY.selectUserAttributesByTypeAndMasterKeyIdMapper(AutoValue_UserPacket_UserAttribute::new);
|
FACTORY.selectUserAttributesByTypeAndMasterKeyIdMapper(AutoValue_UserPacket_UserAttribute::new);
|
||||||
|
public static final UidStatusMapper<UidStatus> UID_STATUS_MAPPER =
|
||||||
|
FACTORY.selectUserIdStatusByEmailMapper(AutoValue_UserPacket_UidStatus::new);
|
||||||
|
|
||||||
public static UserPacket create(long masterKeyId, int rank, Long type, String userId, String name, String email,
|
public static UserPacket create(long masterKeyId, int rank, Long type, String userId, String name, String email,
|
||||||
String comment, byte[] attribute_data, boolean isPrimary, boolean isRevoked) {
|
String comment, byte[] attribute_data, boolean isPrimary, boolean isRevoked) {
|
||||||
@@ -55,4 +57,11 @@ public abstract class UserPacket implements UserPacketsModel {
|
|||||||
return CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode(verified_int());
|
return CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode(verified_int());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AutoValue
|
||||||
|
public static abstract class UidStatus implements UidStatusModel {
|
||||||
|
public VerificationStatus keyStatus() {
|
||||||
|
return CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode(key_status_int());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,12 +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.model.UserPacket.UidStatus;
|
||||||
|
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.Keys;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||||
@@ -248,7 +252,7 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
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) {
|
if (queriesUidResult) {
|
||||||
fillTempTableWithUidResult(db, isWildcardSelector);
|
fillTempTableWithUidResult(db, isWildcardSelector, selectionArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean queriesAutocryptResult = plist.contains(AutocryptStatus.AUTOCRYPT_PEER_STATE) ||
|
boolean queriesAutocryptResult = plist.contains(AutocryptStatus.AUTOCRYPT_PEER_STATE) ||
|
||||||
@@ -343,44 +347,32 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillTempTableWithUidResult(SupportSQLiteDatabase db, boolean isWildcardSelector) {
|
private void fillTempTableWithUidResult(SupportSQLiteDatabase db,
|
||||||
String cmpOperator = isWildcardSelector ? " LIKE " : " = ";
|
boolean isWildcardSelector, String[] selectionArgs) {
|
||||||
long unixSeconds = System.currentTimeMillis() / 1000;
|
SqlDelightQuery query;
|
||||||
db.execSQL("REPLACE INTO " + TEMP_TABLE_QUERIED_ADDRESSES +
|
if (isWildcardSelector) {
|
||||||
"(" + TEMP_TABLE_COLUMN_ADDRES + ", " + AutocryptStatus.UID_KEY_STATUS + ", " +
|
query = UserPacket.FACTORY.selectUserIdStatusByEmailLike(selectionArgs[0]);
|
||||||
AutocryptStatus.UID_ADDRESS + ", " + AutocryptStatus.UID_MASTER_KEY_ID
|
} else {
|
||||||
+ ", " + AutocryptStatus.UID_CANDIDATES + ")" +
|
query = UserPacket.FACTORY.selectUserIdStatusByEmail(selectionArgs);
|
||||||
" SELECT " + TEMP_TABLE_COLUMN_ADDRES + ", " +
|
}
|
||||||
"CASE ( MIN (" + Tables.CERTS + "." + Certs.VERIFIED + " ) ) "
|
|
||||||
// remap to keep this provider contract independent from our internal representation
|
try (Cursor cursor = db.query(query)) {
|
||||||
+ " WHEN " + Certs.VERIFIED_SELF + " THEN " + KeychainExternalContract.KEY_STATUS_UNVERIFIED
|
ContentValues cv = new ContentValues();
|
||||||
+ " WHEN " + Certs.VERIFIED_SECRET + " THEN " + KeychainExternalContract.KEY_STATUS_VERIFIED
|
while (cursor.moveToNext()) {
|
||||||
+ " END AS " + AutocryptStatus.UID_KEY_STATUS
|
UidStatus uidStatus = UserPacket.UID_STATUS_MAPPER.map(cursor);
|
||||||
+ ", " + Tables.USER_PACKETS + "." + UserPackets.USER_ID
|
int keyStatus = uidStatus.keyStatus() == VerificationStatus.VERIFIED_SECRET ?
|
||||||
+ ", " + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID
|
KeychainExternalContract.KEY_STATUS_VERIFIED : KeychainExternalContract.KEY_STATUS_UNVERIFIED;
|
||||||
+ ", COUNT(DISTINCT " + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + ")"
|
|
||||||
+ " FROM " + TEMP_TABLE_QUERIED_ADDRESSES
|
cv.put(AutocryptStatus.UID_ADDRESS, uidStatus.user_id());
|
||||||
+ " LEFT JOIN " + Tables.USER_PACKETS + " ON ("
|
cv.put(AutocryptStatus.UID_MASTER_KEY_ID, uidStatus.master_key_id());
|
||||||
+ Tables.USER_PACKETS + "." + UserPackets.EMAIL + cmpOperator +
|
cv.put(AutocryptStatus.UID_KEY_STATUS, keyStatus);
|
||||||
TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES
|
cv.put(AutocryptStatus.UID_CANDIDATES, uidStatus.candidates());
|
||||||
+ ")"
|
|
||||||
+ " LEFT JOIN " + Tables.CERTS + " ON ("
|
db.update(TEMP_TABLE_QUERIED_ADDRESSES, SQLiteDatabase.CONFLICT_IGNORE, cv,
|
||||||
+ Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = " + Tables.USER_PACKETS + "." +
|
TEMP_TABLE_COLUMN_ADDRES + "= ?",
|
||||||
UserPackets.MASTER_KEY_ID
|
new String[] { isWildcardSelector ? selectionArgs[0] : uidStatus.email() });
|
||||||
+ " AND " + Tables.CERTS + "." + Certs.RANK + " = " + Tables.USER_PACKETS + "." +
|
}
|
||||||
UserPackets.RANK
|
}
|
||||||
+ " AND " + Tables.CERTS + "." + Certs.VERIFIED + " > 0"
|
|
||||||
+ ")"
|
|
||||||
+ " WHERE (EXISTS (SELECT 1 FROM " + Tables.KEYS + " WHERE "
|
|
||||||
+ Tables.KEYS + "." + Keys.KEY_ID + " = " + Tables.USER_PACKETS + "." +
|
|
||||||
UserPackets.MASTER_KEY_ID
|
|
||||||
+ " AND " + Tables.KEYS + "." + Keys.RANK + " = 0"
|
|
||||||
+ " AND " + Tables.KEYS + "." + Keys.IS_REVOKED + " = 0"
|
|
||||||
+ " AND NOT " + "(" + Tables.KEYS + "." + Keys.EXPIRY + " IS NOT NULL AND " + Tables.KEYS +
|
|
||||||
"." + Keys.EXPIRY
|
|
||||||
+ " < " + unixSeconds + ")"
|
|
||||||
+ ")) OR " + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " IS NULL"
|
|
||||||
+ " GROUP BY " + TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPeerStateValue(AutocryptState autocryptState) {
|
private int getPeerStateValue(AutocryptState autocryptState) {
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ UPDATE keys
|
|||||||
SET has_secret = ?2
|
SET has_secret = ?2
|
||||||
WHERE key_id = ?1;
|
WHERE key_id = ?1;
|
||||||
|
|
||||||
|
validKeysView:
|
||||||
|
CREATE VIEW validMasterKeys AS
|
||||||
|
SELECT *
|
||||||
|
FROM keys
|
||||||
|
WHERE rank = 0 AND is_revoked = 0 AND is_secure = 1 AND (expiry IS NULL OR expiry >= strftime('%s', 'now'));
|
||||||
|
|
||||||
unifiedKeyView:
|
unifiedKeyView:
|
||||||
CREATE VIEW unifiedKeyView AS
|
CREATE VIEW unifiedKeyView AS
|
||||||
SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.user_id, user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, keys.can_certify, certs.verified,
|
SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.user_id, user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, keys.can_certify, certs.verified,
|
||||||
|
|||||||
@@ -49,3 +49,23 @@ SELECT user_packets.master_key_id, user_packets.rank, attribute_data, is_primary
|
|||||||
LEFT JOIN certs ON ( user_packets.master_key_id = certs.master_key_id AND user_packets.rank = certs.rank AND certs.verified > 0 )
|
LEFT JOIN certs ON ( user_packets.master_key_id = certs.master_key_id AND user_packets.rank = certs.rank AND certs.verified > 0 )
|
||||||
WHERE user_packets.type = ? AND user_packets.master_key_id = ? AND user_packets.rank = ?
|
WHERE user_packets.type = ? AND user_packets.master_key_id = ? AND user_packets.rank = ?
|
||||||
GROUP BY user_packets.master_key_id, user_packets.rank;
|
GROUP BY user_packets.master_key_id, user_packets.rank;
|
||||||
|
|
||||||
|
|
||||||
|
uidStatus:
|
||||||
|
CREATE VIEW uidStatus AS
|
||||||
|
SELECT user_packets.email, MIN(certs.verified) AS key_status_int, user_packets.user_id, user_packets.master_key_id, COUNT(DISTINCT user_packets.master_key_id) AS candidates
|
||||||
|
FROM user_packets
|
||||||
|
JOIN validMasterKeys USING (master_key_id)
|
||||||
|
LEFT JOIN certs ON (certs.master_key_id = user_packets.master_key_id AND certs.rank = user_packets.rank AND certs.verified > 0)
|
||||||
|
WHERE user_packets.email IS NOT NULL
|
||||||
|
GROUP BY user_packets.email;
|
||||||
|
|
||||||
|
selectUserIdStatusByEmail:
|
||||||
|
SELECT *
|
||||||
|
FROM uidStatus
|
||||||
|
WHERE email IN ?;
|
||||||
|
|
||||||
|
selectUserIdStatusByEmailLike:
|
||||||
|
SELECT *
|
||||||
|
FROM uidStatus
|
||||||
|
WHERE email LIKE ?;
|
||||||
|
|||||||
Reference in New Issue
Block a user