diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index 517717867..b6b8750e4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -166,8 +166,6 @@ public class KeychainDatabase extends SQLiteOpenHelper { + ApiTrustIdentityColumns.MASTER_KEY_ID + " INTEGER NOT NULL, " + "PRIMARY KEY(" + ApiTrustIdentityColumns.PACKAGE_NAME + ", " + ApiTrustIdentityColumns.IDENTIFIER + "), " - + "FOREIGN KEY(" + ApiTrustIdentityColumns.MASTER_KEY_ID + ") REFERENCES " - + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE, " + "FOREIGN KEY(" + ApiTrustIdentityColumns.PACKAGE_NAME + ") REFERENCES " + Tables.API_APPS + "(" + ApiAppsColumns.PACKAGE_NAME + ") ON DELETE CASCADE" + ")"; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainExternalContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainExternalContract.java index d09046831..e28089e6f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainExternalContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainExternalContract.java @@ -44,6 +44,7 @@ public class KeychainExternalContract { public static final String USER_ID_STATUS = "email_status"; public static final String MASTER_KEY_ID = "master_key_id"; public static final String TRUST_ID_LAST_UPDATE = "trust_id_last_update"; + public static final String TRUST_ID_STATUS = "trust_id_status"; public static final Uri CONTENT_URI = BASE_CONTENT_URI_EXTERNAL.buildUpon() .appendPath(BASE_EMAIL_STATUS).build(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/KeychainExternalProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/KeychainExternalProvider.java index 83eb7af4a..5caa9675f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/KeychainExternalProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/KeychainExternalProvider.java @@ -174,12 +174,18 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC projectionMap.put(EmailStatus.USER_ID, Tables.USER_PACKETS + "." + UserPackets.USER_ID + " AS " + EmailStatus.USER_ID); // we take the minimum (>0) here, where "1" is "verified by known secret key", "2" is "self-certified" - projectionMap.put(EmailStatus.USER_ID_STATUS, "CASE ( MIN (" + Certs.VERIFIED + " ) ) " + projectionMap.put(EmailStatus.USER_ID_STATUS, "CASE ( MIN (certs_user_id." + Certs.VERIFIED + " ) ) " // remap to keep this provider contract independent from our internal representation + " WHEN " + Certs.VERIFIED_SELF + " THEN " + KeychainExternalContract.KEY_STATUS_UNVERIFIED + " WHEN " + Certs.VERIFIED_SECRET + " THEN " + KeychainExternalContract.KEY_STATUS_VERIFIED - + " WHEN NULL THEN " + KeychainExternalContract.KEY_STATUS_UNVERIFIED + + " WHEN NULL THEN NULL" + " END AS " + EmailStatus.USER_ID_STATUS); + projectionMap.put(EmailStatus.TRUST_ID_STATUS, "CASE ( MIN (certs_trust_id." + Certs.VERIFIED + " ) ) " + // remap to keep this provider contract independent from our internal representation + + " WHEN " + Certs.VERIFIED_SELF + " THEN " + KeychainExternalContract.KEY_STATUS_UNVERIFIED + + " WHEN " + Certs.VERIFIED_SECRET + " THEN " + KeychainExternalContract.KEY_STATUS_VERIFIED + + " WHEN NULL THEN NULL" + + " END AS " + EmailStatus.TRUST_ID_STATUS); projectionMap.put(EmailStatus.MASTER_KEY_ID, Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " AS " + EmailStatus.MASTER_KEY_ID); projectionMap.put(EmailStatus.USER_ID, @@ -198,28 +204,25 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC + Tables.USER_PACKETS + "." + UserPackets.USER_ID + " IS NOT NULL" + " AND " + Tables.USER_PACKETS + "." + UserPackets.EMAIL + " LIKE " + TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES + ")" + + " LEFT JOIN " + Tables.CERTS + " AS certs_user_id ON (" + + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = certs_user_id." + Certs.MASTER_KEY_ID + + " AND " + Tables.USER_PACKETS + "." + UserPackets.RANK + " = certs_user_id." + Certs.RANK + + ")" + " LEFT JOIN " + Tables.API_TRUST_IDENTITIES + " ON (" + Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.IDENTIFIER + " LIKE queried_addresses.address" + " AND " + Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.PACKAGE_NAME + " = \"" + callingPackageName + "\"" + ")" - + " JOIN " + Tables.CERTS + " ON (" - + "(" + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = " + Tables.CERTS + "." + Certs.MASTER_KEY_ID - + " AND " + Tables.USER_PACKETS + "." + UserPackets.RANK + " = " + Tables.CERTS + "." + Certs.RANK + ")" - + " OR " + Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.MASTER_KEY_ID + " = " + Tables.CERTS + "." + Certs.MASTER_KEY_ID + + " LEFT JOIN " + Tables.CERTS + " AS certs_trust_id ON (" + + Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.MASTER_KEY_ID + " = certs_trust_id." + Certs.MASTER_KEY_ID + ")" ); // in case there are multiple verifying certificates - groupBy = TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES - + ", " + Tables.CERTS + "." + UserPackets.MASTER_KEY_ID; + groupBy = TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES; List plist = Arrays.asList(projection); if (plist.contains(EmailStatus.USER_ID)) { groupBy += ", " + Tables.USER_PACKETS + "." + UserPackets.USER_ID; } - // verified == 0 has no self-cert, which is basically an error case. never return that! - // verified == null is fine, because it means there was no join partner - qb.appendWhere(Tables.CERTS + "." + Certs.VERIFIED + " IS NULL OR " + Tables.CERTS + "." + Certs.VERIFIED + " > 0"); - if (TextUtils.isEmpty(sortOrder)) { sortOrder = EmailStatus.EMAIL_ADDRESS; } diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/remote/KeychainExternalProviderTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/remote/KeychainExternalProviderTest.java index 98623da74..d9f1457da 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/remote/KeychainExternalProviderTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/remote/KeychainExternalProviderTest.java @@ -3,6 +3,7 @@ package org.sufficientlysecure.keychain.remote; import java.security.AccessControlException; import java.util.Collections; +import java.util.Date; import android.content.ContentResolver; import android.content.pm.PackageInfo; @@ -23,6 +24,7 @@ import org.sufficientlysecure.keychain.provider.ApiDataAccessObject; import org.sufficientlysecure.keychain.provider.KeyWritableRepository; import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus; import org.sufficientlysecure.keychain.provider.KeyRepositorySaveTest; +import org.sufficientlysecure.keychain.provider.TrustIdentityDataAccessObject; import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -43,6 +45,7 @@ public class KeychainExternalProviderTest { static final String USER_ID_SEC_1 = "twi "; static final long KEY_ID_SECRET = 0x5D4DA4423C39122FL; static final long KEY_ID_PUBLIC = 0x9A282CE2AB44A382L; + public static final String TRUST_ID = "tid"; KeyWritableRepository databaseInteractor = @@ -50,6 +53,7 @@ public class KeychainExternalProviderTest { ContentResolver contentResolver = RuntimeEnvironment.application.getContentResolver(); ApiPermissionHelper apiPermissionHelper; ApiDataAccessObject apiDao; + private TrustIdentityDataAccessObject trustIdDao; @Before @@ -63,6 +67,7 @@ public class KeychainExternalProviderTest { apiDao = new ApiDataAccessObject(RuntimeEnvironment.application); apiPermissionHelper = new ApiPermissionHelper(RuntimeEnvironment.application, apiDao); + trustIdDao = new TrustIdentityDataAccessObject(RuntimeEnvironment.application, PACKAGE_NAME); apiDao.insertApiApp(new AppSettings(PACKAGE_NAME, PACKAGE_SIGNATURE)); } @@ -173,7 +178,54 @@ public class KeychainExternalProviderTest { } @Test - public void testQuery__withConfirmedKey() throws Exception { + public void testQuery__trustId__withUnconfirmedKey() throws Exception { + insertSecretKeyringFrom("/test-keys/testring.sec"); + insertPublicKeyringFrom("/test-keys/testring.pub"); + + trustIdDao.setMasterKeyIdForTrustId("tid", KEY_ID_PUBLIC, new Date()); + + Cursor cursor = contentResolver.query( + EmailStatus.CONTENT_URI, new String[] { + EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID_STATUS, EmailStatus.USER_ID, + EmailStatus.TRUST_ID_STATUS }, + null, new String [] { TRUST_ID }, null + ); + + assertNotNull(cursor); + assertTrue(cursor.moveToFirst()); + assertEquals("tid", cursor.getString(0)); + assertEquals(null, cursor.getString(2)); + assertEquals(0, cursor.getInt(1)); + assertEquals(1, cursor.getInt(3)); + assertFalse(cursor.moveToNext()); + } + + @Test + public void testQuery__trustId__withConfirmedKey() throws Exception { + insertSecretKeyringFrom("/test-keys/testring.sec"); + insertPublicKeyringFrom("/test-keys/testring.pub"); + + trustIdDao.setMasterKeyIdForTrustId("tid", KEY_ID_PUBLIC, new Date()); + certifyKey(KEY_ID_SECRET, KEY_ID_PUBLIC, USER_ID_1); + + Cursor cursor = contentResolver.query( + EmailStatus.CONTENT_URI, new String[] { + EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID_STATUS, EmailStatus.USER_ID, + EmailStatus.TRUST_ID_STATUS }, + null, new String [] { TRUST_ID }, null + ); + + assertNotNull(cursor); + assertTrue(cursor.moveToFirst()); + assertEquals("tid", cursor.getString(0)); + assertEquals(null, cursor.getString(2)); + assertEquals(0, cursor.getInt(1)); + assertEquals(2, cursor.getInt(3)); + assertFalse(cursor.moveToNext()); + } + + @Test + public void testQuery__withTrustId() throws Exception { insertSecretKeyringFrom("/test-keys/testring.sec"); insertPublicKeyringFrom("/test-keys/testring.pub");