return key status differently for uid and autocrypt peer in KeychainExternalProvider
This commit is contained in:
@@ -119,37 +119,30 @@ public class AutocryptPeerDataAccessObject {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMasterKeyIdForAutocryptPeer(String autocryptId, long masterKeyId, Date date) {
|
public void updateToResetState(String autocryptId, Date effectiveDate) {
|
||||||
Date lastUpdated = getLastSeen(autocryptId);
|
updateAutocryptState(autocryptId, effectiveDate, null, ApiAutocryptPeer.RESET);
|
||||||
if (lastUpdated != null && lastUpdated.after(date)) {
|
|
||||||
throw new IllegalArgumentException("Database entry was newer than the one to be inserted! Cannot backdate");
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentValues cv = new ContentValues();
|
|
||||||
cv.put(ApiAutocryptPeer.MASTER_KEY_ID, masterKeyId);
|
|
||||||
cv.put(ApiAutocryptPeer.LAST_SEEN_KEY, date.getTime());
|
|
||||||
mQueryInterface.update(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), cv, null, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateToResetState(String autocryptId, Date effectiveDate) {
|
public void updateToGossipState(String autocryptId, Date effectiveDate, long masterKeyId) {
|
||||||
updateAutocryptState(autocryptId, effectiveDate, ApiAutocryptPeer.RESET);
|
updateAutocryptState(autocryptId, effectiveDate, masterKeyId, ApiAutocryptPeer.GOSSIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateToMutualState(String autocryptId, Date effectiveDate, long masterKeyId) {
|
public void updateToMutualState(String autocryptId, Date effectiveDate, long masterKeyId) {
|
||||||
setMasterKeyIdForAutocryptPeer(autocryptId, masterKeyId, effectiveDate);
|
updateAutocryptState(autocryptId, effectiveDate, masterKeyId, ApiAutocryptPeer.MUTUAL);
|
||||||
updateAutocryptState(autocryptId, effectiveDate, ApiAutocryptPeer.MUTUAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateToAvailableState(String autocryptId, Date effectiveDate, long masterKeyId) {
|
public void updateToAvailableState(String autocryptId, Date effectiveDate, long masterKeyId) {
|
||||||
setMasterKeyIdForAutocryptPeer(autocryptId, masterKeyId, effectiveDate);
|
updateAutocryptState(autocryptId, effectiveDate, masterKeyId, ApiAutocryptPeer.AVAILABLE);
|
||||||
updateAutocryptState(autocryptId, effectiveDate, ApiAutocryptPeer.AVAILABLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAutocryptState(String autocryptId, Date date, int status) {
|
private void updateAutocryptState(String autocryptId, Date date, Long masterKeyId, int status) {
|
||||||
ContentValues cv = new ContentValues();
|
ContentValues cv = new ContentValues();
|
||||||
cv.put(ApiAutocryptPeer.MASTER_KEY_ID, (Integer) null);
|
cv.put(ApiAutocryptPeer.MASTER_KEY_ID, masterKeyId);
|
||||||
cv.put(ApiAutocryptPeer.LAST_SEEN, date.getTime());
|
cv.put(ApiAutocryptPeer.LAST_SEEN, date.getTime());
|
||||||
cv.put(ApiAutocryptPeer.STATUS, status);
|
if (masterKeyId != null) {
|
||||||
|
cv.put(ApiAutocryptPeer.LAST_SEEN_KEY, masterKeyId);
|
||||||
|
}
|
||||||
|
cv.put(ApiAutocryptPeer.STATE, status);
|
||||||
mQueryInterface.update(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), cv, null, null);
|
mQueryInterface.update(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), cv, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ public class KeychainContract {
|
|||||||
String IDENTIFIER = "identifier";
|
String IDENTIFIER = "identifier";
|
||||||
String LAST_SEEN = "last_updated";
|
String LAST_SEEN = "last_updated";
|
||||||
String LAST_SEEN_KEY = "last_seen_key";
|
String LAST_SEEN_KEY = "last_seen_key";
|
||||||
String STATUS = "status";
|
String STATE = "state";
|
||||||
String MASTER_KEY_ID = "master_key_id";
|
String MASTER_KEY_ID = "master_key_id";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
|||||||
+ ApiAutocryptPeerColumns.IDENTIFIER + " TEXT NOT NULL, "
|
+ ApiAutocryptPeerColumns.IDENTIFIER + " TEXT NOT NULL, "
|
||||||
+ ApiAutocryptPeerColumns.LAST_SEEN + " INTEGER NOT NULL, "
|
+ ApiAutocryptPeerColumns.LAST_SEEN + " INTEGER NOT NULL, "
|
||||||
+ ApiAutocryptPeerColumns.LAST_SEEN_KEY + " INTEGER NOT NULL, "
|
+ ApiAutocryptPeerColumns.LAST_SEEN_KEY + " INTEGER NOT NULL, "
|
||||||
+ ApiAutocryptPeerColumns.STATUS + " INTEGER NOT NULL, "
|
+ ApiAutocryptPeerColumns.STATE + " INTEGER NOT NULL, "
|
||||||
+ ApiAutocryptPeerColumns.MASTER_KEY_ID + " INTEGER NULL, "
|
+ ApiAutocryptPeerColumns.MASTER_KEY_ID + " INTEGER NULL, "
|
||||||
+ "PRIMARY KEY(" + ApiAutocryptPeerColumns.PACKAGE_NAME + ", "
|
+ "PRIMARY KEY(" + ApiAutocryptPeerColumns.PACKAGE_NAME + ", "
|
||||||
+ ApiAutocryptPeerColumns.IDENTIFIER + "), "
|
+ ApiAutocryptPeerColumns.IDENTIFIER + "), "
|
||||||
|
|||||||
@@ -26,9 +26,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAutocryptPee
|
|||||||
|
|
||||||
|
|
||||||
public class KeychainExternalContract {
|
public class KeychainExternalContract {
|
||||||
public static final int KEY_STATUS_UNAVAILABLE = 0;
|
|
||||||
public static final int KEY_STATUS_UNVERIFIED = 1;
|
|
||||||
public static final int KEY_STATUS_VERIFIED = 2;
|
|
||||||
|
|
||||||
// this is in KeychainExternalContract already, but we want to be double
|
// this is in KeychainExternalContract already, but we want to be double
|
||||||
// sure this isn't mixed up with the internal one!
|
// sure this isn't mixed up with the internal one!
|
||||||
@@ -36,15 +33,31 @@ public class KeychainExternalContract {
|
|||||||
private static final Uri BASE_CONTENT_URI_EXTERNAL = Uri
|
private static final Uri BASE_CONTENT_URI_EXTERNAL = Uri
|
||||||
.parse("content://" + CONTENT_AUTHORITY_EXTERNAL);
|
.parse("content://" + CONTENT_AUTHORITY_EXTERNAL);
|
||||||
public static final String BASE_EMAIL_STATUS = "email_status";
|
public static final String BASE_EMAIL_STATUS = "email_status";
|
||||||
public static final String BASE_AUTOCRYPT_PEER_STATUS = "autocrypt_status";
|
|
||||||
public static final String BASE_AUTOCRYPT_PEERS = "autocrypt_peers";
|
public static final String BASE_AUTOCRYPT_PEERS = "autocrypt_peers";
|
||||||
|
|
||||||
|
|
||||||
public static class EmailStatus implements BaseColumns {
|
public static class EmailStatus implements BaseColumns {
|
||||||
public static final String EMAIL_ADDRESS = "email_address";
|
public static final String ADDRESS = "address";
|
||||||
public static final String USER_ID = "user_id";
|
|
||||||
public static final String USER_ID_STATUS = "email_status";
|
public static final String UID_ADDRESS = "uid_address";
|
||||||
public static final String MASTER_KEY_ID = "master_key_id";
|
public static final String UID_KEY_STATUS = "uid_key_status";
|
||||||
|
public static final String UID_MASTER_KEY_ID = "uid_master_key_id";
|
||||||
|
public static final String UID_CANDIDATES = "uid_candidates";
|
||||||
|
|
||||||
|
public static final String AUTOCRYPT_MASTER_KEY_ID = "autocrypt_master_key_id";
|
||||||
|
public static final String AUTOCRYPT_KEY_STATUS = "autocrypt_key_status";
|
||||||
|
public static final String AUTOCRYPT_PEER_STATE = "autocrypt_peer_state";
|
||||||
|
public static final String AUTOCRYPT_LAST_SEEN = "autocrypt_last_seen";
|
||||||
|
public static final String AUTOCRYPT_LAST_SEEN_KEY = "autocrypt_last_seen_key";
|
||||||
|
|
||||||
|
public static final int KEY_STATUS_UNAVAILABLE = 0;
|
||||||
|
public static final int KEY_STATUS_UNVERIFIED = 1;
|
||||||
|
public static final int KEY_STATUS_VERIFIED = 2;
|
||||||
|
|
||||||
|
public static final int AUTOCRYPT_PEER_RESET = 0;
|
||||||
|
public static final int AUTOCRYPT_PEER_GOSSIP = 1;
|
||||||
|
public static final int AUTOCRYPT_PEER_AVAILABLE = 2;
|
||||||
|
public static final int AUTOCRYPT_PEER_MUTUAL = 3;
|
||||||
|
|
||||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_EXTERNAL.buildUpon()
|
public static final Uri CONTENT_URI = BASE_CONTENT_URI_EXTERNAL.buildUpon()
|
||||||
.appendPath(BASE_EMAIL_STATUS).build();
|
.appendPath(BASE_EMAIL_STATUS).build();
|
||||||
@@ -53,19 +66,6 @@ public class KeychainExternalContract {
|
|||||||
"vnd.android.cursor.dir/vnd.org.sufficientlysecure.keychain.provider.email_status";
|
"vnd.android.cursor.dir/vnd.org.sufficientlysecure.keychain.provider.email_status";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class AutocryptPeerStatus implements BaseColumns {
|
|
||||||
public static final String EMAIL_ADDRESS = "email_address";
|
|
||||||
public static final String MASTER_KEY_ID = "master_key_id";
|
|
||||||
public static final String AUTOCRYPT_PEER_LAST_SEEN = "autocrypt_peer_last_seen";
|
|
||||||
public static final String AUTOCRYPT_PEER_STATUS = "autocrypt_peer_state";
|
|
||||||
|
|
||||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_EXTERNAL.buildUpon()
|
|
||||||
.appendPath(BASE_EMAIL_STATUS).build();
|
|
||||||
|
|
||||||
public static final String CONTENT_TYPE =
|
|
||||||
"vnd.android.cursor.dir/vnd.org.sufficientlysecure.keychain.provider.autocrypt_status";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ApiAutocryptPeer implements ApiAutocryptPeerColumns, BaseColumns {
|
public static class ApiAutocryptPeer implements ApiAutocryptPeerColumns, BaseColumns {
|
||||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_EXTERNAL.buildUpon()
|
public static final Uri CONTENT_URI = BASE_CONTENT_URI_EXTERNAL.buildUpon()
|
||||||
.appendPath(BASE_AUTOCRYPT_PEERS).build();
|
.appendPath(BASE_AUTOCRYPT_PEERS).build();
|
||||||
|
|||||||
@@ -999,7 +999,6 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
case TRUST_IDS_BY_PACKAGE_NAME_AND_TRUST_ID: {
|
case TRUST_IDS_BY_PACKAGE_NAME_AND_TRUST_ID: {
|
||||||
Long masterKeyId = values.getAsLong(ApiAutocryptPeer.MASTER_KEY_ID);
|
Long masterKeyId = values.getAsLong(ApiAutocryptPeer.MASTER_KEY_ID);
|
||||||
long updateTime = values.getAsLong(ApiAutocryptPeer.LAST_SEEN);
|
|
||||||
if (masterKeyId == null) {
|
if (masterKeyId == null) {
|
||||||
throw new IllegalArgumentException("master_key_id must be a non-null value!");
|
throw new IllegalArgumentException("master_key_id must be a non-null value!");
|
||||||
}
|
}
|
||||||
@@ -1009,7 +1008,20 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
actualValues.put(ApiAutocryptPeer.PACKAGE_NAME, packageName);
|
actualValues.put(ApiAutocryptPeer.PACKAGE_NAME, packageName);
|
||||||
actualValues.put(ApiAutocryptPeer.IDENTIFIER, uri.getLastPathSegment());
|
actualValues.put(ApiAutocryptPeer.IDENTIFIER, uri.getLastPathSegment());
|
||||||
actualValues.put(ApiAutocryptPeer.MASTER_KEY_ID, masterKeyId);
|
actualValues.put(ApiAutocryptPeer.MASTER_KEY_ID, masterKeyId);
|
||||||
actualValues.put(ApiAutocryptPeer.LAST_SEEN, updateTime);
|
|
||||||
|
Long newLastSeen = values.getAsLong(ApiAutocryptPeer.LAST_SEEN);
|
||||||
|
if (newLastSeen != null) {
|
||||||
|
actualValues.put(ApiAutocryptPeer.LAST_SEEN, newLastSeen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.containsKey(ApiAutocryptPeer.LAST_SEEN_KEY)) {
|
||||||
|
actualValues.put(ApiAutocryptPeer.LAST_SEEN_KEY,
|
||||||
|
values.getAsLong(ApiAutocryptPeer.LAST_SEEN_KEY));
|
||||||
|
}
|
||||||
|
if (values.containsKey(ApiAutocryptPeer.STATE)) {
|
||||||
|
actualValues.put(ApiAutocryptPeer.STATE,
|
||||||
|
values.getAsLong(ApiAutocryptPeer.STATE));
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.replace(Tables.API_AUTOCRYPT_PEERS, null, actualValues);
|
db.replace(Tables.API_AUTOCRYPT_PEERS, null, actualValues);
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import java.security.AccessControlException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
import android.content.ContentProvider;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
@@ -48,7 +47,6 @@ import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
|||||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
|
import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.ApiAutocryptPeer;
|
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.ApiAutocryptPeer;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptPeerStatus;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus;
|
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus;
|
||||||
import org.sufficientlysecure.keychain.provider.SimpleContentResolverInterface;
|
import org.sufficientlysecure.keychain.provider.SimpleContentResolverInterface;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
@@ -59,8 +57,6 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
|
|||||||
private static final int AUTOCRYPT_PEER = 201;
|
private static final int AUTOCRYPT_PEER = 201;
|
||||||
private static final int API_APPS = 301;
|
private static final int API_APPS = 301;
|
||||||
private static final int API_APPS_BY_PACKAGE_NAME = 302;
|
private static final int API_APPS_BY_PACKAGE_NAME = 302;
|
||||||
private static final int AUTOCRYPT_PEER_STATUS = 401;
|
|
||||||
private static final int AUTOCRYPT_PEER_STATUS_INTERNAL = 402;
|
|
||||||
|
|
||||||
public static final String TEMP_TABLE_QUERIED_ADDRESSES = "queried_addresses";
|
public static final String TEMP_TABLE_QUERIED_ADDRESSES = "queried_addresses";
|
||||||
public static final String TEMP_TABLE_COLUMN_ADDRES = "address";
|
public static final String TEMP_TABLE_COLUMN_ADDRES = "address";
|
||||||
@@ -91,9 +87,6 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
|
|||||||
|
|
||||||
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_PEERS + "/*", AUTOCRYPT_PEER);
|
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_PEERS + "/*", AUTOCRYPT_PEER);
|
||||||
|
|
||||||
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_PEER_STATUS, AUTOCRYPT_PEER_STATUS);
|
|
||||||
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_PEER_STATUS + "/*", AUTOCRYPT_PEER_STATUS_INTERNAL);
|
|
||||||
|
|
||||||
// can only query status of calling app - for internal use only!
|
// can only query status of calling app - for internal use only!
|
||||||
matcher.addURI(KeychainContract.CONTENT_AUTHORITY, KeychainContract.BASE_API_APPS + "/*", API_APPS_BY_PACKAGE_NAME);
|
matcher.addURI(KeychainContract.CONTENT_AUTHORITY, KeychainContract.BASE_API_APPS + "/*", API_APPS_BY_PACKAGE_NAME);
|
||||||
|
|
||||||
@@ -120,9 +113,6 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
|
|||||||
final int match = mUriMatcher.match(uri);
|
final int match = mUriMatcher.match(uri);
|
||||||
switch (match) {
|
switch (match) {
|
||||||
case EMAIL_STATUS:
|
case EMAIL_STATUS:
|
||||||
case EMAIL_STATUS_INTERNAL:
|
|
||||||
case AUTOCRYPT_PEER_STATUS:
|
|
||||||
case AUTOCRYPT_PEER_STATUS_INTERNAL:
|
|
||||||
return EmailStatus.CONTENT_TYPE;
|
return EmailStatus.CONTENT_TYPE;
|
||||||
|
|
||||||
case API_APPS:
|
case API_APPS:
|
||||||
@@ -178,21 +168,38 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
|
|||||||
|
|
||||||
HashMap<String, String> projectionMap = new HashMap<>();
|
HashMap<String, String> projectionMap = new HashMap<>();
|
||||||
projectionMap.put(EmailStatus._ID, "email AS _id");
|
projectionMap.put(EmailStatus._ID, "email AS _id");
|
||||||
projectionMap.put(EmailStatus.EMAIL_ADDRESS, // this is actually the queried address
|
projectionMap.put(EmailStatus.ADDRESS, // this is actually the queried address
|
||||||
TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES + " AS " + EmailStatus.EMAIL_ADDRESS);
|
TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES + " AS " + EmailStatus.ADDRESS);
|
||||||
projectionMap.put(EmailStatus.USER_ID,
|
|
||||||
Tables.USER_PACKETS + "." + UserPackets.USER_ID + " AS " + EmailStatus.USER_ID);
|
projectionMap.put(EmailStatus.UID_ADDRESS,
|
||||||
|
Tables.USER_PACKETS + "." + UserPackets.USER_ID + " AS " + EmailStatus.UID_ADDRESS);
|
||||||
// we take the minimum (>0) here, where "1" is "verified by known secret key", "2" is "self-certified"
|
// 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_user_id." + Certs.VERIFIED + " ) ) "
|
projectionMap.put(EmailStatus.UID_KEY_STATUS, "CASE ( MIN (certs_user_id." + Certs.VERIFIED + " ) ) "
|
||||||
// remap to keep this provider contract independent from our internal representation
|
// remap to keep this provider contract independent from our internal representation
|
||||||
+ " WHEN " + Certs.VERIFIED_SELF + " THEN " + KeychainExternalContract.KEY_STATUS_UNVERIFIED
|
+ " WHEN " + Certs.VERIFIED_SELF + " THEN " + EmailStatus.KEY_STATUS_UNVERIFIED
|
||||||
+ " WHEN " + Certs.VERIFIED_SECRET + " THEN " + KeychainExternalContract.KEY_STATUS_VERIFIED
|
+ " WHEN " + Certs.VERIFIED_SECRET + " THEN " + EmailStatus.KEY_STATUS_VERIFIED
|
||||||
+ " WHEN NULL THEN NULL"
|
+ " WHEN NULL THEN NULL"
|
||||||
+ " END AS " + EmailStatus.USER_ID_STATUS);
|
+ " END AS " + EmailStatus.UID_KEY_STATUS);
|
||||||
projectionMap.put(EmailStatus.MASTER_KEY_ID,
|
projectionMap.put(EmailStatus.UID_MASTER_KEY_ID,
|
||||||
Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " AS " + EmailStatus.MASTER_KEY_ID);
|
Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " AS " + EmailStatus.UID_MASTER_KEY_ID);
|
||||||
projectionMap.put(EmailStatus.USER_ID,
|
projectionMap.put(EmailStatus.UID_CANDIDATES,
|
||||||
Tables.USER_PACKETS + "." + UserPackets.USER_ID + " AS " + EmailStatus.USER_ID);
|
"COUNT(DISTINCT " + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID +
|
||||||
|
") AS " + EmailStatus.UID_CANDIDATES);
|
||||||
|
|
||||||
|
projectionMap.put(EmailStatus.AUTOCRYPT_KEY_STATUS, "CASE ( MIN (certs_autocrypt_peer." + Certs.VERIFIED + " ) ) "
|
||||||
|
// remap to keep this provider contract independent from our internal representation
|
||||||
|
+ " WHEN " + Certs.VERIFIED_SELF + " THEN " + EmailStatus.KEY_STATUS_UNVERIFIED
|
||||||
|
+ " WHEN " + Certs.VERIFIED_SECRET + " THEN " + EmailStatus.KEY_STATUS_VERIFIED
|
||||||
|
+ " WHEN NULL THEN NULL"
|
||||||
|
+ " END AS " + EmailStatus.AUTOCRYPT_KEY_STATUS);
|
||||||
|
projectionMap.put(EmailStatus.AUTOCRYPT_MASTER_KEY_ID,
|
||||||
|
Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.MASTER_KEY_ID + " AS " + EmailStatus.AUTOCRYPT_MASTER_KEY_ID);
|
||||||
|
projectionMap.put(EmailStatus.AUTOCRYPT_PEER_STATE, Tables.API_AUTOCRYPT_PEERS + "." +
|
||||||
|
ApiAutocryptPeer.STATE + " AS " + EmailStatus.AUTOCRYPT_LAST_SEEN_KEY);
|
||||||
|
projectionMap.put(EmailStatus.AUTOCRYPT_LAST_SEEN, Tables.API_AUTOCRYPT_PEERS + "." +
|
||||||
|
ApiAutocryptPeer.LAST_SEEN + " AS " + EmailStatus.AUTOCRYPT_LAST_SEEN);
|
||||||
|
projectionMap.put(EmailStatus.AUTOCRYPT_LAST_SEEN_KEY, Tables.API_AUTOCRYPT_PEERS + "." +
|
||||||
|
ApiAutocryptPeer.LAST_SEEN_KEY + " AS " + EmailStatus.AUTOCRYPT_LAST_SEEN_KEY);
|
||||||
qb.setProjectionMap(projectionMap);
|
qb.setProjectionMap(projectionMap);
|
||||||
|
|
||||||
if (projection == null) {
|
if (projection == null) {
|
||||||
@@ -209,66 +216,6 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
|
|||||||
+ Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = certs_user_id." + Certs.MASTER_KEY_ID
|
+ 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
|
+ " AND " + Tables.USER_PACKETS + "." + UserPackets.RANK + " = certs_user_id." + Certs.RANK
|
||||||
+ ")"
|
+ ")"
|
||||||
);
|
|
||||||
// in case there are multiple verifying certificates
|
|
||||||
groupBy = TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES;
|
|
||||||
List<String> plist = Arrays.asList(projection);
|
|
||||||
if (plist.contains(EmailStatus.USER_ID)) {
|
|
||||||
groupBy += ", " + Tables.USER_PACKETS + "." + UserPackets.USER_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(sortOrder)) {
|
|
||||||
sortOrder = EmailStatus.EMAIL_ADDRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// uri to watch is all /key_rings/
|
|
||||||
uri = KeyRings.CONTENT_URI;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case AUTOCRYPT_PEER_STATUS_INTERNAL:
|
|
||||||
if (!BuildConfig.APPLICATION_ID.equals(callingPackageName)) {
|
|
||||||
throw new AccessControlException("This URI can only be called internally!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// override package name to use any external
|
|
||||||
// callingPackageName = uri.getLastPathSegment();
|
|
||||||
|
|
||||||
case AUTOCRYPT_PEER_STATUS: {
|
|
||||||
boolean callerIsAllowed = (match == AUTOCRYPT_PEER_STATUS_INTERNAL) || mApiPermissionHelper.isAllowedIgnoreErrors();
|
|
||||||
if (!callerIsAllowed) {
|
|
||||||
throw new AccessControlException("An application must register before use of KeychainExternalProvider!");
|
|
||||||
}
|
|
||||||
|
|
||||||
db.execSQL("CREATE TEMPORARY TABLE " + TEMP_TABLE_QUERIED_ADDRESSES + " (" + TEMP_TABLE_COLUMN_ADDRES + " TEXT);");
|
|
||||||
ContentValues cv = new ContentValues();
|
|
||||||
for (String address : selectionArgs) {
|
|
||||||
cv.put(TEMP_TABLE_COLUMN_ADDRES, address);
|
|
||||||
db.insert(TEMP_TABLE_QUERIED_ADDRESSES, null, cv);
|
|
||||||
}
|
|
||||||
|
|
||||||
HashMap<String, String> projectionMap = new HashMap<>();
|
|
||||||
projectionMap.put(AutocryptPeerStatus._ID, "email AS _id");
|
|
||||||
projectionMap.put(AutocryptPeerStatus.EMAIL_ADDRESS, // this is actually the queried address
|
|
||||||
TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES + " AS " + AutocryptPeerStatus.EMAIL_ADDRESS);
|
|
||||||
projectionMap.put(AutocryptPeerStatus.AUTOCRYPT_PEER_STATUS, "CASE ( MIN (certs_autocrypt_peer." + 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 " + AutocryptPeerStatus.AUTOCRYPT_PEER_STATUS);
|
|
||||||
projectionMap.put(AutocryptPeerStatus.MASTER_KEY_ID,
|
|
||||||
Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " AS " + AutocryptPeerStatus.MASTER_KEY_ID);
|
|
||||||
projectionMap.put(AutocryptPeerStatus.AUTOCRYPT_PEER_LAST_SEEN, Tables.API_AUTOCRYPT_PEERS + "." +
|
|
||||||
ApiAutocryptPeer.LAST_SEEN + " AS " + AutocryptPeerStatus.AUTOCRYPT_PEER_LAST_SEEN);
|
|
||||||
qb.setProjectionMap(projectionMap);
|
|
||||||
|
|
||||||
if (projection == null) {
|
|
||||||
throw new IllegalArgumentException("Please provide a projection!");
|
|
||||||
}
|
|
||||||
|
|
||||||
qb.setTables(
|
|
||||||
TEMP_TABLE_QUERIED_ADDRESSES
|
|
||||||
+ " LEFT JOIN " + Tables.API_AUTOCRYPT_PEERS + " ON ("
|
+ " LEFT JOIN " + Tables.API_AUTOCRYPT_PEERS + " ON ("
|
||||||
+ Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.IDENTIFIER + " LIKE queried_addresses.address"
|
+ Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.IDENTIFIER + " LIKE queried_addresses.address"
|
||||||
+ " AND " + Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.PACKAGE_NAME + " = \"" + callingPackageName + "\""
|
+ " AND " + Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.PACKAGE_NAME + " = \"" + callingPackageName + "\""
|
||||||
@@ -279,10 +226,9 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
|
|||||||
);
|
);
|
||||||
// in case there are multiple verifying certificates
|
// in case there are multiple verifying certificates
|
||||||
groupBy = TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES;
|
groupBy = TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES;
|
||||||
List<String> plist = Arrays.asList(projection);
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(sortOrder)) {
|
if (TextUtils.isEmpty(sortOrder)) {
|
||||||
sortOrder = TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES;
|
sortOrder = EmailStatus.ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// uri to watch is all /key_rings/
|
// uri to watch is all /key_rings/
|
||||||
@@ -305,6 +251,7 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
|
|||||||
projectionMap.put(ApiAutocryptPeer.IDENTIFIER, ApiAutocryptPeer.IDENTIFIER);
|
projectionMap.put(ApiAutocryptPeer.IDENTIFIER, ApiAutocryptPeer.IDENTIFIER);
|
||||||
projectionMap.put(ApiAutocryptPeer.MASTER_KEY_ID, ApiAutocryptPeer.MASTER_KEY_ID);
|
projectionMap.put(ApiAutocryptPeer.MASTER_KEY_ID, ApiAutocryptPeer.MASTER_KEY_ID);
|
||||||
projectionMap.put(ApiAutocryptPeer.LAST_SEEN, ApiAutocryptPeer.LAST_SEEN);
|
projectionMap.put(ApiAutocryptPeer.LAST_SEEN, ApiAutocryptPeer.LAST_SEEN);
|
||||||
|
projectionMap.put(ApiAutocryptPeer.LAST_SEEN_KEY, ApiAutocryptPeer.LAST_SEEN_KEY);
|
||||||
qb.setProjectionMap(projectionMap);
|
qb.setProjectionMap(projectionMap);
|
||||||
|
|
||||||
qb.setTables(Tables.API_AUTOCRYPT_PEERS);
|
qb.setTables(Tables.API_AUTOCRYPT_PEERS);
|
||||||
|
|||||||
@@ -606,7 +606,7 @@ public class OpenPgpService extends Service {
|
|||||||
|
|
||||||
long masterKeyId = signatureResult.getKeyId();
|
long masterKeyId = signatureResult.getKeyId();
|
||||||
if (autocryptPeerMasterKeyId == null) {
|
if (autocryptPeerMasterKeyId == null) {
|
||||||
autocryptPeerentityDao.setMasterKeyIdForAutocryptPeer(autocryptPeerentity, masterKeyId, new Date());
|
autocryptPeerentityDao.updateToGossipState(autocryptPeerentity, new Date(), masterKeyId);
|
||||||
return signatureResult.withAutocryptPeerResult(AutocryptPeerResult.NEW);
|
return signatureResult.withAutocryptPeerResult(AutocryptPeerResult.NEW);
|
||||||
} else if (masterKeyId == autocryptPeerMasterKeyId) {
|
} else if (masterKeyId == autocryptPeerMasterKeyId) {
|
||||||
return signatureResult.withAutocryptPeerResult(AutocryptPeerResult.OK);
|
return signatureResult.withAutocryptPeerResult(AutocryptPeerResult.OK);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ package org.sufficientlysecure.keychain.remote;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
@@ -17,7 +16,6 @@ import android.support.annotation.VisibleForTesting;
|
|||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
|
import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptPeerStatus;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus;
|
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
@@ -26,22 +24,21 @@ import org.sufficientlysecure.keychain.util.Log;
|
|||||||
class OpenPgpServiceKeyIdExtractor {
|
class OpenPgpServiceKeyIdExtractor {
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String[] PROJECTION_MAIL_STATUS = {
|
static final String[] PROJECTION_MAIL_STATUS = {
|
||||||
EmailStatus.EMAIL_ADDRESS,
|
EmailStatus.ADDRESS,
|
||||||
EmailStatus.MASTER_KEY_ID,
|
EmailStatus.UID_MASTER_KEY_ID,
|
||||||
EmailStatus.USER_ID_STATUS,
|
EmailStatus.UID_KEY_STATUS,
|
||||||
|
EmailStatus.UID_CANDIDATES,
|
||||||
|
EmailStatus.AUTOCRYPT_MASTER_KEY_ID,
|
||||||
|
EmailStatus.AUTOCRYPT_KEY_STATUS,
|
||||||
|
EmailStatus.AUTOCRYPT_PEER_STATE
|
||||||
};
|
};
|
||||||
private static final int INDEX_EMAIL_ADDRESS = 0;
|
private static final int INDEX_EMAIL_ADDRESS = 0;
|
||||||
private static final int INDEX_MASTER_KEY_ID = 1;
|
private static final int INDEX_MASTER_KEY_ID = 1;
|
||||||
private static final int INDEX_USER_ID_STATUS = 2;
|
private static final int INDEX_USER_ID_STATUS = 2;
|
||||||
|
private static final int INDEX_USER_ID_CANDIDATES = 3;
|
||||||
static final String[] PROJECTION_AUTOCRYPT = {
|
private static final int INDEX_AUTOCRYPT_MASTER_KEY_ID = 4;
|
||||||
AutocryptPeerStatus.EMAIL_ADDRESS,
|
private static final int INDEX_AUTOCRYPT_KEY_STATUS = 5;
|
||||||
AutocryptPeerStatus.MASTER_KEY_ID,
|
private static final int INDEX_AUTOCRYPT_PEER_STATE = 6;
|
||||||
AutocryptPeerStatus.AUTOCRYPT_PEER_STATUS,
|
|
||||||
};
|
|
||||||
private static final int INDEX_AUTOCRYPT_ADDRESS = 0;
|
|
||||||
private static final int INDEX_AUTOCRYPT_MASTER_KEY_ID = 1;
|
|
||||||
private static final int INDEX_AUTOCRYPT_STATUS = 2;
|
|
||||||
|
|
||||||
|
|
||||||
private final ApiPendingIntentFactory apiPendingIntentFactory;
|
private final ApiPendingIntentFactory apiPendingIntentFactory;
|
||||||
@@ -97,33 +94,33 @@ class OpenPgpServiceKeyIdExtractor {
|
|||||||
ArrayList<String> duplicateEmails = new ArrayList<>();
|
ArrayList<String> duplicateEmails = new ArrayList<>();
|
||||||
|
|
||||||
if (hasAddresses) {
|
if (hasAddresses) {
|
||||||
HashMap<String, UserIdStatus> keyRows = getStatusMapForQueriedAddresses(encryptionAddresses, callingPackageName);
|
HashMap<String, AddressQueryResult> userIdEntries = getStatusMapForQueriedAddresses(
|
||||||
HashMap<String, AutocryptRecommendation> autocryptRows = getAutocryptRecommendationsForQueriedAddresses(
|
|
||||||
encryptionAddresses, callingPackageName);
|
encryptionAddresses, callingPackageName);
|
||||||
|
|
||||||
boolean anyKeyNotVerified = false;
|
boolean anyKeyNotVerified = false;
|
||||||
for (Entry<String, UserIdStatus> entry : keyRows.entrySet()) {
|
for (String queriedAddress : encryptionAddresses) {
|
||||||
String queriedAddress = entry.getKey();
|
AddressQueryResult addressQueryResult = userIdEntries.get(queriedAddress);
|
||||||
UserIdStatus userIdStatus = entry.getValue();
|
if (addressQueryResult == null) {
|
||||||
|
throw new IllegalStateException("No result for address - shouldn't happen!");
|
||||||
|
}
|
||||||
|
|
||||||
if (userIdStatus.masterKeyId == null) {
|
if (addressQueryResult.uidMasterKeyId != null) {
|
||||||
|
keyIds.add(addressQueryResult.uidMasterKeyId);
|
||||||
|
|
||||||
|
if (addressQueryResult.uidHasMultipleCandidates) {
|
||||||
|
duplicateEmails.add(queriedAddress);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
missingEmails.add(queriedAddress);
|
missingEmails.add(queriedAddress);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
keyIds.add(userIdStatus.masterKeyId);
|
if (addressQueryResult.uidKeyStatus != EmailStatus.KEY_STATUS_VERIFIED) {
|
||||||
|
|
||||||
if (userIdStatus.hasDuplicate) {
|
|
||||||
duplicateEmails.add(queriedAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userIdStatus.userIdVerified != KeychainExternalContract.KEY_STATUS_VERIFIED &&
|
|
||||||
userIdStatus.autocryptPeerVerified != KeychainExternalContract.KEY_STATUS_VERIFIED) {
|
|
||||||
anyKeyNotVerified = true;
|
anyKeyNotVerified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyRows.size() != encryptionAddresses.length) {
|
if (userIdEntries.size() != encryptionAddresses.length) {
|
||||||
Log.e(Constants.TAG, "Number of rows doesn't match number of retrieved rows! Probably a bug?");
|
Log.e(Constants.TAG, "Number of rows doesn't match number of retrieved rows! Probably a bug?");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,8 +148,8 @@ class OpenPgpServiceKeyIdExtractor {
|
|||||||
* verification status exist, the first one is returned and marked as having a duplicate.
|
* verification status exist, the first one is returned and marked as having a duplicate.
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private HashMap<String, UserIdStatus> getStatusMapForQueriedAddresses(String[] encryptionUserIds, String callingPackageName) {
|
private HashMap<String, AddressQueryResult> getStatusMapForQueriedAddresses(String[] encryptionUserIds, String callingPackageName) {
|
||||||
HashMap<String,UserIdStatus> keyRows = new HashMap<>();
|
HashMap<String,AddressQueryResult> keyRows = new HashMap<>();
|
||||||
Uri queryUri = EmailStatus.CONTENT_URI.buildUpon().appendPath(callingPackageName).build();
|
Uri queryUri = EmailStatus.CONTENT_URI.buildUpon().appendPath(callingPackageName).build();
|
||||||
Cursor cursor = contentResolver.query(queryUri, PROJECTION_MAIL_STATUS, null, encryptionUserIds, null);
|
Cursor cursor = contentResolver.query(queryUri, PROJECTION_MAIL_STATUS, null, encryptionUserIds, null);
|
||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
@@ -162,36 +159,21 @@ class OpenPgpServiceKeyIdExtractor {
|
|||||||
try {
|
try {
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
String queryAddress = cursor.getString(INDEX_EMAIL_ADDRESS);
|
String queryAddress = cursor.getString(INDEX_EMAIL_ADDRESS);
|
||||||
Long masterKeyId = cursor.isNull(INDEX_MASTER_KEY_ID) ? null : cursor.getLong(INDEX_MASTER_KEY_ID);
|
Long uidMasterKeyId =
|
||||||
int userIdStatus = cursor.getInt(INDEX_USER_ID_STATUS);
|
cursor.isNull(INDEX_MASTER_KEY_ID) ? null : cursor.getLong(INDEX_MASTER_KEY_ID);
|
||||||
|
int uidKeyStatus = cursor.getInt(INDEX_USER_ID_STATUS);
|
||||||
|
boolean uidHasMultipleCandidates = cursor.getInt(INDEX_USER_ID_CANDIDATES) > 1;
|
||||||
|
|
||||||
AutocryptRecommendation autocryptRecommendation;
|
Long autocryptMasterKeyId =
|
||||||
if (cursor.getInt(INDEX_AUTOCRYPT_PEER_STATUS) == KeychainExternalContract.KEY_STATUS_UNAVAILABLE) {
|
cursor.isNull(INDEX_AUTOCRYPT_MASTER_KEY_ID) ? null : cursor.getLong(INDEX_AUTOCRYPT_MASTER_KEY_ID);
|
||||||
autocryptRecommendation = AutocryptRecommendation.UNAVAILABLE;
|
int autocryptKeyStatus = cursor.getInt(INDEX_AUTOCRYPT_KEY_STATUS);
|
||||||
} else {
|
int autocryptPeerStatus = cursor.getInt(INDEX_AUTOCRYPT_PEER_STATE);
|
||||||
// TODO encourage/discourage, based on gossip/ state
|
|
||||||
autocryptRecommendation = AutocryptRecommendation.AVAILABLE;
|
|
||||||
}
|
|
||||||
UserIdStatus status = new UserIdStatus(masterKeyId, userIdStatus, autocryptRecommendation);
|
|
||||||
|
|
||||||
boolean seenBefore = keyRows.containsKey(queryAddress);
|
AddressQueryResult
|
||||||
if (!seenBefore) {
|
status = new AddressQueryResult(uidMasterKeyId, uidKeyStatus, uidHasMultipleCandidates,
|
||||||
keyRows.put(queryAddress, status);
|
autocryptMasterKeyId, autocryptKeyStatus, autocryptPeerStatus);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserIdStatus previousUserIdStatus = keyRows.get(queryAddress);
|
keyRows.put(queryAddress, status);
|
||||||
if (previousUserIdStatus.autocryptPeerVerified != KeychainExternalContract.KEY_STATUS_UNAVAILABLE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previousUserIdStatus.masterKeyId == null) {
|
|
||||||
keyRows.put(queryAddress, status);
|
|
||||||
} else if (previousUserIdStatus.userIdVerified < status.userIdVerified) {
|
|
||||||
keyRows.put(queryAddress, status);
|
|
||||||
} else if (previousUserIdStatus.userIdVerified == status.userIdVerified) {
|
|
||||||
previousUserIdStatus.hasDuplicate = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
@@ -199,51 +181,28 @@ class OpenPgpServiceKeyIdExtractor {
|
|||||||
return keyRows;
|
return keyRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This method queries the KeychainExternalProvider for all addresses given in encryptionUserIds.
|
private static class AddressQueryResult {
|
||||||
* It returns a map with one UserIdStatus per queried address. If multiple key candidates exist,
|
private final Long uidMasterKeyId;
|
||||||
* the one with the highest verification status is selected. If two candidates with the same
|
private final int uidKeyStatus;
|
||||||
* verification status exist, the first one is returned and marked as having a duplicate.
|
private boolean uidHasMultipleCandidates;
|
||||||
*/
|
private final Long autocryptMasterKeyId;
|
||||||
@NonNull
|
private final int autocryptKeyStatus;
|
||||||
private HashMap<String, AutocryptRecommendation> getAutocryptRecommendationsForQueriedAddresses(
|
private final int autocryptState;
|
||||||
String[] encryptionUserIds, String callingPackageName) {
|
|
||||||
Uri queryUri = AutocryptPeerStatus.CONTENT_URI.buildUpon().appendPath(callingPackageName).build();
|
|
||||||
Cursor cursor = contentResolver.query(queryUri, PROJECTION_AUTOCRYPT, null, encryptionUserIds, null);
|
|
||||||
if (cursor == null) {
|
|
||||||
throw new IllegalStateException("Internal error, received null cursor!");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
AddressQueryResult(Long uidMasterKeyId, int uidKeyStatus, boolean uidHasMultipleCandidates, Long autocryptMasterKeyId,
|
||||||
HashMap<String,UserIdStatus> keyRows = new HashMap<>();
|
int autocryptKeyStatus,
|
||||||
while (cursor.moveToNext()) {
|
int autocryptState) {
|
||||||
String queryAddress = cursor.getString(INDEX_AUTOCRYPT_ADDRESS);
|
this.uidMasterKeyId = uidMasterKeyId;
|
||||||
Long masterKeyId = cursor.isNull(INDEX_AUTOCRYPT_MASTER_KEY_ID) ?
|
this.uidKeyStatus = uidKeyStatus;
|
||||||
null : cursor.getLong(INDEX_AUTOCRYPT_MASTER_KEY_ID);
|
this.uidHasMultipleCandidates = uidHasMultipleCandidates;
|
||||||
int autocryptStatus = cursor.getInt(INDEX_AUTOCRYPT_STATUS);
|
this.autocryptMasterKeyId = autocryptMasterKeyId;
|
||||||
|
this.autocryptKeyStatus = autocryptKeyStatus;
|
||||||
AutocryptRecommendation autocryptRecommendation;
|
this.autocryptState = autocryptState;
|
||||||
if (cursor.getInt(INDEX_AUTOCRYPT_STATUS) == KeychainExternalContract.KEY_STATUS_UNAVAILABLE) {
|
|
||||||
autocryptRecommendation = AutocryptRecommendation.UNAVAILABLE;
|
|
||||||
} else {
|
|
||||||
// TODO encourage/discourage, based on gossip/ state
|
|
||||||
autocryptRecommendation = AutocryptRecommendation.AVAILABLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
return keyRows;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class UserIdStatus {
|
enum AutocryptState {
|
||||||
private final Long masterKeyId;
|
UNAVAILABLE, DISCOURAGE, AVAILABLE, MUTUAL
|
||||||
private final int userIdVerified;
|
|
||||||
private boolean hasDuplicate;
|
|
||||||
|
|
||||||
UserIdStatus(Long masterKeyId, int userIdVerified) {
|
|
||||||
this.masterKeyId = masterKeyId;
|
|
||||||
this.userIdVerified = userIdVerified;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class KeyIdResult {
|
static class KeyIdResult {
|
||||||
@@ -317,10 +276,6 @@ class OpenPgpServiceKeyIdExtractor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AutocryptRecommendation {
|
|
||||||
UNAVAILABLE, DISCOURAGE, AVAILABLE, MUTUAL
|
|
||||||
}
|
|
||||||
|
|
||||||
enum KeyIdResultStatus {
|
enum KeyIdResultStatus {
|
||||||
OK, MISSING, DUPLICATE, NO_KEYS, NO_KEYS_ERROR
|
OK, MISSING, DUPLICATE, NO_KEYS, NO_KEYS_ERROR
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,22 +15,26 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.res.builder.RobolectricPackageManager;
|
import org.robolectric.res.builder.RobolectricPackageManager;
|
||||||
|
import org.robolectric.shadows.ShadowLog;
|
||||||
import org.sufficientlysecure.keychain.KeychainTestRunner;
|
import org.sufficientlysecure.keychain.KeychainTestRunner;
|
||||||
import org.sufficientlysecure.keychain.operations.CertifyOperation;
|
import org.sufficientlysecure.keychain.operations.CertifyOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||||
import org.sufficientlysecure.keychain.provider.ApiDataAccessObject;
|
import org.sufficientlysecure.keychain.provider.ApiDataAccessObject;
|
||||||
|
import org.sufficientlysecure.keychain.provider.AutocryptPeerDataAccessObject;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeyRepositorySaveTest;
|
||||||
import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
|
import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus;
|
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus;
|
||||||
import org.sufficientlysecure.keychain.provider.KeyRepositorySaveTest;
|
|
||||||
import org.sufficientlysecure.keychain.provider.AutocryptPeerDataAccessObject;
|
|
||||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
||||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
|
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
@@ -58,6 +62,8 @@ public class KeychainExternalProviderTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
|
ShadowLog.stream = System.out;
|
||||||
|
|
||||||
RobolectricPackageManager rpm = (RobolectricPackageManager) RuntimeEnvironment.getPackageManager();
|
RobolectricPackageManager rpm = (RobolectricPackageManager) RuntimeEnvironment.getPackageManager();
|
||||||
rpm.setPackagesForUid(0, PACKAGE_NAME);
|
rpm.setPackagesForUid(0, PACKAGE_NAME);
|
||||||
PackageInfo packageInfo = new PackageInfo();
|
PackageInfo packageInfo = new PackageInfo();
|
||||||
@@ -78,7 +84,7 @@ public class KeychainExternalProviderTest {
|
|||||||
|
|
||||||
contentResolver.query(
|
contentResolver.query(
|
||||||
EmailStatus.CONTENT_URI,
|
EmailStatus.CONTENT_URI,
|
||||||
new String[] { EmailStatus.EMAIL_ADDRESS, EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID },
|
new String[] { EmailStatus.ADDRESS, EmailStatus.ADDRESS, EmailStatus.UID_ADDRESS },
|
||||||
null, new String [] { }, null
|
null, new String [] { }, null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -87,7 +93,7 @@ public class KeychainExternalProviderTest {
|
|||||||
public void testPermission__withExplicitPackage() throws Exception {
|
public void testPermission__withExplicitPackage() throws Exception {
|
||||||
contentResolver.query(
|
contentResolver.query(
|
||||||
EmailStatus.CONTENT_URI.buildUpon().appendPath("fake_pkg").build(),
|
EmailStatus.CONTENT_URI.buildUpon().appendPath("fake_pkg").build(),
|
||||||
new String[] { EmailStatus.EMAIL_ADDRESS, EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID },
|
new String[] { EmailStatus.ADDRESS, EmailStatus.ADDRESS, EmailStatus.UID_ADDRESS },
|
||||||
null, new String [] { }, null
|
null, new String [] { }, null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -99,7 +105,7 @@ public class KeychainExternalProviderTest {
|
|||||||
|
|
||||||
contentResolver.query(
|
contentResolver.query(
|
||||||
EmailStatus.CONTENT_URI,
|
EmailStatus.CONTENT_URI,
|
||||||
new String[] { EmailStatus.EMAIL_ADDRESS, EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID },
|
new String[] { EmailStatus.ADDRESS, EmailStatus.ADDRESS, EmailStatus.UID_ADDRESS },
|
||||||
null, new String [] { }, null
|
null, new String [] { }, null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -108,14 +114,14 @@ public class KeychainExternalProviderTest {
|
|||||||
public void testQuery__withNonExistentAddress() throws Exception {
|
public void testQuery__withNonExistentAddress() throws Exception {
|
||||||
Cursor cursor = contentResolver.query(
|
Cursor cursor = contentResolver.query(
|
||||||
EmailStatus.CONTENT_URI, new String[] {
|
EmailStatus.CONTENT_URI, new String[] {
|
||||||
EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID_STATUS, EmailStatus.USER_ID },
|
EmailStatus.ADDRESS, EmailStatus.UID_KEY_STATUS, EmailStatus.UID_ADDRESS },
|
||||||
null, new String [] { MAIL_ADDRESS_1 }, null
|
null, new String [] { MAIL_ADDRESS_1 }, null
|
||||||
);
|
);
|
||||||
|
|
||||||
assertNotNull(cursor);
|
assertNotNull(cursor);
|
||||||
assertTrue(cursor.moveToFirst());
|
assertTrue(cursor.moveToFirst());
|
||||||
assertEquals(MAIL_ADDRESS_1, cursor.getString(0));
|
assertEquals(MAIL_ADDRESS_1, cursor.getString(0));
|
||||||
assertEquals(0, cursor.getInt(1));
|
assertEquals(EmailStatus.KEY_STATUS_UNAVAILABLE, cursor.getInt(1));
|
||||||
assertTrue(cursor.isNull(2));
|
assertTrue(cursor.isNull(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,14 +131,14 @@ public class KeychainExternalProviderTest {
|
|||||||
|
|
||||||
Cursor cursor = contentResolver.query(
|
Cursor cursor = contentResolver.query(
|
||||||
EmailStatus.CONTENT_URI, new String[] {
|
EmailStatus.CONTENT_URI, new String[] {
|
||||||
EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID_STATUS, EmailStatus.USER_ID },
|
EmailStatus.ADDRESS, EmailStatus.UID_KEY_STATUS, EmailStatus.UID_ADDRESS },
|
||||||
null, new String [] { MAIL_ADDRESS_1 }, null
|
null, new String [] { MAIL_ADDRESS_1 }, null
|
||||||
);
|
);
|
||||||
|
|
||||||
assertNotNull(cursor);
|
assertNotNull(cursor);
|
||||||
assertTrue(cursor.moveToFirst());
|
assertTrue(cursor.moveToFirst());
|
||||||
assertEquals(MAIL_ADDRESS_1, cursor.getString(0));
|
assertEquals(MAIL_ADDRESS_1, cursor.getString(0));
|
||||||
assertEquals(1, cursor.getInt(1));
|
assertEquals(EmailStatus.KEY_STATUS_UNVERIFIED, cursor.getInt(1));
|
||||||
assertEquals("twi <twi@openkeychain.org>", cursor.getString(2));
|
assertEquals("twi <twi@openkeychain.org>", cursor.getString(2));
|
||||||
assertFalse(cursor.moveToNext());
|
assertFalse(cursor.moveToNext());
|
||||||
}
|
}
|
||||||
@@ -143,18 +149,18 @@ public class KeychainExternalProviderTest {
|
|||||||
|
|
||||||
Cursor cursor = contentResolver.query(
|
Cursor cursor = contentResolver.query(
|
||||||
EmailStatus.CONTENT_URI, new String[] {
|
EmailStatus.CONTENT_URI, new String[] {
|
||||||
EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID_STATUS, EmailStatus.USER_ID },
|
EmailStatus.ADDRESS, EmailStatus.UID_KEY_STATUS, EmailStatus.UID_ADDRESS },
|
||||||
null, new String [] { MAIL_ADDRESS_1, MAIL_ADDRESS_2 }, null
|
null, new String [] { MAIL_ADDRESS_1, MAIL_ADDRESS_2 }, null
|
||||||
);
|
);
|
||||||
|
|
||||||
assertNotNull(cursor);
|
assertNotNull(cursor);
|
||||||
assertTrue(cursor.moveToNext());
|
assertTrue(cursor.moveToNext());
|
||||||
assertEquals(MAIL_ADDRESS_2, cursor.getString(0));
|
assertEquals(MAIL_ADDRESS_2, cursor.getString(0));
|
||||||
assertEquals(0, cursor.getInt(1));
|
assertEquals(EmailStatus.KEY_STATUS_UNAVAILABLE, cursor.getInt(1));
|
||||||
assertTrue(cursor.isNull(2));
|
assertTrue(cursor.isNull(2));
|
||||||
assertTrue(cursor.moveToNext());
|
assertTrue(cursor.moveToNext());
|
||||||
assertEquals(MAIL_ADDRESS_1, cursor.getString(0));
|
assertEquals(MAIL_ADDRESS_1, cursor.getString(0));
|
||||||
assertEquals(1, cursor.getInt(1));
|
assertEquals(EmailStatus.KEY_STATUS_UNVERIFIED, cursor.getInt(1));
|
||||||
assertEquals("twi <twi@openkeychain.org>", cursor.getString(2));
|
assertEquals("twi <twi@openkeychain.org>", cursor.getString(2));
|
||||||
assertFalse(cursor.moveToNext());
|
assertFalse(cursor.moveToNext());
|
||||||
}
|
}
|
||||||
@@ -165,7 +171,7 @@ public class KeychainExternalProviderTest {
|
|||||||
|
|
||||||
Cursor cursor = contentResolver.query(
|
Cursor cursor = contentResolver.query(
|
||||||
EmailStatus.CONTENT_URI, new String[] {
|
EmailStatus.CONTENT_URI, new String[] {
|
||||||
EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID_STATUS, EmailStatus.USER_ID },
|
EmailStatus.ADDRESS, EmailStatus.UID_KEY_STATUS, EmailStatus.UID_ADDRESS },
|
||||||
null, new String [] { MAIL_ADDRESS_SEC_1 }, null
|
null, new String [] { MAIL_ADDRESS_SEC_1 }, null
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -182,21 +188,25 @@ public class KeychainExternalProviderTest {
|
|||||||
insertSecretKeyringFrom("/test-keys/testring.sec");
|
insertSecretKeyringFrom("/test-keys/testring.sec");
|
||||||
insertPublicKeyringFrom("/test-keys/testring.pub");
|
insertPublicKeyringFrom("/test-keys/testring.pub");
|
||||||
|
|
||||||
autocryptPeerDao.setMasterKeyIdForAutocryptPeer("tid", KEY_ID_PUBLIC, new Date());
|
autocryptPeerDao.updateToAvailableState("tid", new Date(), KEY_ID_PUBLIC);
|
||||||
|
|
||||||
Cursor cursor = contentResolver.query(
|
Cursor cursor = contentResolver.query(
|
||||||
EmailStatus.CONTENT_URI, new String[] {
|
EmailStatus.CONTENT_URI, new String[] {
|
||||||
EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID_STATUS, EmailStatus.USER_ID,
|
EmailStatus.ADDRESS, EmailStatus.UID_KEY_STATUS, EmailStatus.UID_ADDRESS,
|
||||||
EmailStatus.AUTOCRYPT_PEER_STATUS },
|
EmailStatus.AUTOCRYPT_KEY_STATUS, EmailStatus.AUTOCRYPT_MASTER_KEY_ID,
|
||||||
|
EmailStatus.AUTOCRYPT_PEER_STATE
|
||||||
|
},
|
||||||
null, new String [] { AUTOCRYPT_PEER }, null
|
null, new String [] { AUTOCRYPT_PEER }, null
|
||||||
);
|
);
|
||||||
|
|
||||||
assertNotNull(cursor);
|
assertNotNull(cursor);
|
||||||
assertTrue(cursor.moveToFirst());
|
assertTrue(cursor.moveToFirst());
|
||||||
assertEquals("tid", cursor.getString(0));
|
assertEquals("tid", cursor.getString(0));
|
||||||
|
assertTrue(cursor.isNull(1));
|
||||||
assertEquals(null, cursor.getString(2));
|
assertEquals(null, cursor.getString(2));
|
||||||
assertEquals(0, cursor.getInt(1));
|
assertEquals(EmailStatus.KEY_STATUS_UNVERIFIED, cursor.getInt(3));
|
||||||
assertEquals(1, cursor.getInt(3));
|
assertEquals(KEY_ID_PUBLIC, cursor.getLong(4));
|
||||||
|
assertEquals(EmailStatus.AUTOCRYPT_PEER_AVAILABLE, cursor.getInt(5));
|
||||||
assertFalse(cursor.moveToNext());
|
assertFalse(cursor.moveToNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,22 +215,48 @@ public class KeychainExternalProviderTest {
|
|||||||
insertSecretKeyringFrom("/test-keys/testring.sec");
|
insertSecretKeyringFrom("/test-keys/testring.sec");
|
||||||
insertPublicKeyringFrom("/test-keys/testring.pub");
|
insertPublicKeyringFrom("/test-keys/testring.pub");
|
||||||
|
|
||||||
autocryptPeerDao.setMasterKeyIdForAutocryptPeer("tid", KEY_ID_PUBLIC, new Date());
|
autocryptPeerDao.updateToAvailableState("tid", new Date(), KEY_ID_PUBLIC);
|
||||||
certifyKey(KEY_ID_SECRET, KEY_ID_PUBLIC, USER_ID_1);
|
certifyKey(KEY_ID_SECRET, KEY_ID_PUBLIC, USER_ID_1);
|
||||||
|
|
||||||
Cursor cursor = contentResolver.query(
|
Cursor cursor = contentResolver.query(
|
||||||
EmailStatus.CONTENT_URI, new String[] {
|
EmailStatus.CONTENT_URI, new String[] {
|
||||||
EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID_STATUS, EmailStatus.USER_ID,
|
EmailStatus.ADDRESS, EmailStatus.UID_KEY_STATUS, EmailStatus.UID_ADDRESS,
|
||||||
EmailStatus.AUTOCRYPT_PEER_STATUS },
|
EmailStatus.AUTOCRYPT_KEY_STATUS, EmailStatus.AUTOCRYPT_PEER_STATE },
|
||||||
null, new String [] { AUTOCRYPT_PEER }, null
|
null, new String [] { AUTOCRYPT_PEER }, null
|
||||||
);
|
);
|
||||||
|
|
||||||
assertNotNull(cursor);
|
assertNotNull(cursor);
|
||||||
assertTrue(cursor.moveToFirst());
|
assertTrue(cursor.moveToFirst());
|
||||||
assertEquals("tid", cursor.getString(0));
|
assertEquals("tid", cursor.getString(0));
|
||||||
|
assertEquals(EmailStatus.KEY_STATUS_UNAVAILABLE, cursor.getInt(1));
|
||||||
assertEquals(null, cursor.getString(2));
|
assertEquals(null, cursor.getString(2));
|
||||||
assertEquals(0, cursor.getInt(1));
|
assertEquals(EmailStatus.KEY_STATUS_VERIFIED, cursor.getInt(3));
|
||||||
assertEquals(2, cursor.getInt(3));
|
assertEquals(EmailStatus.AUTOCRYPT_PEER_AVAILABLE, cursor.getInt(4));
|
||||||
|
assertFalse(cursor.moveToNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQuery__withAutocryptPeer__fromGossip() throws Exception {
|
||||||
|
insertSecretKeyringFrom("/test-keys/testring.sec");
|
||||||
|
insertPublicKeyringFrom("/test-keys/testring.pub");
|
||||||
|
|
||||||
|
autocryptPeerDao.updateToGossipState("tid", new Date(), KEY_ID_PUBLIC);
|
||||||
|
certifyKey(KEY_ID_SECRET, KEY_ID_PUBLIC, USER_ID_1);
|
||||||
|
|
||||||
|
Cursor cursor = contentResolver.query(
|
||||||
|
EmailStatus.CONTENT_URI, new String[] {
|
||||||
|
EmailStatus.ADDRESS, EmailStatus.UID_KEY_STATUS, EmailStatus.UID_ADDRESS,
|
||||||
|
EmailStatus.AUTOCRYPT_KEY_STATUS, EmailStatus.AUTOCRYPT_PEER_STATE },
|
||||||
|
null, new String [] { AUTOCRYPT_PEER }, null
|
||||||
|
);
|
||||||
|
|
||||||
|
assertNotNull(cursor);
|
||||||
|
assertTrue(cursor.moveToFirst());
|
||||||
|
assertEquals("tid", cursor.getString(0));
|
||||||
|
assertEquals(EmailStatus.KEY_STATUS_UNAVAILABLE, cursor.getInt(1));
|
||||||
|
assertEquals(null, cursor.getString(2));
|
||||||
|
assertEquals(EmailStatus.KEY_STATUS_VERIFIED, cursor.getInt(3));
|
||||||
|
assertEquals(EmailStatus.AUTOCRYPT_PEER_GOSSIP, cursor.getInt(4));
|
||||||
assertFalse(cursor.moveToNext());
|
assertFalse(cursor.moveToNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,7 +269,7 @@ public class KeychainExternalProviderTest {
|
|||||||
|
|
||||||
Cursor cursor = contentResolver.query(
|
Cursor cursor = contentResolver.query(
|
||||||
EmailStatus.CONTENT_URI, new String[] {
|
EmailStatus.CONTENT_URI, new String[] {
|
||||||
EmailStatus.EMAIL_ADDRESS, EmailStatus.USER_ID_STATUS, EmailStatus.USER_ID },
|
EmailStatus.ADDRESS, EmailStatus.UID_KEY_STATUS, EmailStatus.UID_ADDRESS },
|
||||||
null, new String [] { MAIL_ADDRESS_1 }, null
|
null, new String [] { MAIL_ADDRESS_1 }, null
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -241,7 +277,7 @@ public class KeychainExternalProviderTest {
|
|||||||
assertTrue(cursor.moveToFirst());
|
assertTrue(cursor.moveToFirst());
|
||||||
assertEquals(MAIL_ADDRESS_1, cursor.getString(0));
|
assertEquals(MAIL_ADDRESS_1, cursor.getString(0));
|
||||||
assertEquals(USER_ID_1, cursor.getString(2));
|
assertEquals(USER_ID_1, cursor.getString(2));
|
||||||
assertEquals(2, cursor.getInt(1));
|
assertEquals(EmailStatus.KEY_STATUS_VERIFIED, cursor.getInt(1));
|
||||||
assertFalse(cursor.moveToNext());
|
assertFalse(cursor.moveToNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class OpenPgpServiceKeyIdExtractorTest {
|
|||||||
assertArrayEqualsSorted(KEY_IDS, keyIdResult.getKeyIds());
|
assertArrayEqualsSorted(KEY_IDS, keyIdResult.getKeyIds());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(expected = IllegalStateException.class)
|
||||||
public void returnKeyIdsFromIntent__withUserIds__withEmptyQueryResult() throws Exception {
|
public void returnKeyIdsFromIntent__withUserIds__withEmptyQueryResult() throws Exception {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, USER_IDS);
|
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, USER_IDS);
|
||||||
@@ -82,15 +82,10 @@ public class OpenPgpServiceKeyIdExtractorTest {
|
|||||||
setupContentResolverResult();
|
setupContentResolverResult();
|
||||||
|
|
||||||
PendingIntent pendingIntent = mock(PendingIntent.class);
|
PendingIntent pendingIntent = mock(PendingIntent.class);
|
||||||
setupPendingIntentFactoryResult(pendingIntent);
|
setupSelectPubkeyPendingIntentFactoryResult(pendingIntent);
|
||||||
|
|
||||||
|
|
||||||
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false,
|
openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false, BuildConfig.APPLICATION_ID);
|
||||||
BuildConfig.APPLICATION_ID);
|
|
||||||
|
|
||||||
|
|
||||||
assertEquals(KeyIdResultStatus.NO_KEYS, keyIdResult.getStatus());
|
|
||||||
assertTrue(keyIdResult.hasKeySelectionPendingIntent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -99,7 +94,7 @@ public class OpenPgpServiceKeyIdExtractorTest {
|
|||||||
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, new String[] { });
|
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, new String[] { });
|
||||||
|
|
||||||
PendingIntent pendingIntent = mock(PendingIntent.class);
|
PendingIntent pendingIntent = mock(PendingIntent.class);
|
||||||
setupPendingIntentFactoryResult(pendingIntent);
|
setupSelectPubkeyPendingIntentFactoryResult(pendingIntent);
|
||||||
|
|
||||||
|
|
||||||
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false,
|
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false,
|
||||||
@@ -117,7 +112,7 @@ public class OpenPgpServiceKeyIdExtractorTest {
|
|||||||
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, new String[0]);
|
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, new String[0]);
|
||||||
|
|
||||||
PendingIntent pendingIntent = mock(PendingIntent.class);
|
PendingIntent pendingIntent = mock(PendingIntent.class);
|
||||||
setupPendingIntentFactoryResult(pendingIntent);
|
setupSelectPubkeyPendingIntentFactoryResult(pendingIntent);
|
||||||
|
|
||||||
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false,
|
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false,
|
||||||
BuildConfig.APPLICATION_ID);
|
BuildConfig.APPLICATION_ID);
|
||||||
@@ -135,7 +130,7 @@ public class OpenPgpServiceKeyIdExtractorTest {
|
|||||||
setupContentResolverResult();
|
setupContentResolverResult();
|
||||||
|
|
||||||
PendingIntent pendingIntent = mock(PendingIntent.class);
|
PendingIntent pendingIntent = mock(PendingIntent.class);
|
||||||
setupPendingIntentFactoryResult(pendingIntent);
|
setupSelectPubkeyPendingIntentFactoryResult(pendingIntent);
|
||||||
|
|
||||||
|
|
||||||
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, true,
|
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, true,
|
||||||
@@ -152,7 +147,7 @@ public class OpenPgpServiceKeyIdExtractorTest {
|
|||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, USER_IDS);
|
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, USER_IDS);
|
||||||
|
|
||||||
setupContentResolverResult(USER_IDS, new Long[] { 123L, 234L }, new int[] { 0, 0 });
|
setupContentResolverResult(USER_IDS, new Long[] { 123L, 234L }, new int[] { 0, 0 }, new int[] { 1, 1, 1 });
|
||||||
|
|
||||||
|
|
||||||
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false,
|
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false,
|
||||||
@@ -170,11 +165,11 @@ public class OpenPgpServiceKeyIdExtractorTest {
|
|||||||
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, USER_IDS);
|
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, USER_IDS);
|
||||||
|
|
||||||
setupContentResolverResult(new String[] {
|
setupContentResolverResult(new String[] {
|
||||||
USER_IDS[0], USER_IDS[0], USER_IDS[1]
|
USER_IDS[0], USER_IDS[1]
|
||||||
}, new Long[] { 123L, 345L, 234L }, new int[] { 0, 0, 0 });
|
}, new Long[] { 123L, 234L }, new int[] { 0, 0 }, new int[] { 2, 1 });
|
||||||
|
|
||||||
PendingIntent pendingIntent = mock(PendingIntent.class);
|
PendingIntent pendingIntent = mock(PendingIntent.class);
|
||||||
setupPendingIntentFactoryResult(pendingIntent);
|
setupDeduplicatePendingIntentFactoryResult(pendingIntent);
|
||||||
|
|
||||||
|
|
||||||
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false,
|
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false,
|
||||||
@@ -190,10 +185,10 @@ public class OpenPgpServiceKeyIdExtractorTest {
|
|||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, USER_IDS);
|
intent.putExtra(OpenPgpApi.EXTRA_USER_IDS, USER_IDS);
|
||||||
|
|
||||||
setupContentResolverResult(USER_IDS, new Long[] { null, 234L }, new int[] { 0, 0 });
|
setupContentResolverResult(USER_IDS, new Long[] { null, 234L }, new int[] { 0, 0 }, new int[] { 0, 1 });
|
||||||
|
|
||||||
PendingIntent pendingIntent = mock(PendingIntent.class);
|
PendingIntent pendingIntent = mock(PendingIntent.class);
|
||||||
setupPendingIntentFactoryResult(pendingIntent);
|
setupSelectPubkeyPendingIntentFactoryResult(pendingIntent);
|
||||||
|
|
||||||
|
|
||||||
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false,
|
KeyIdResult keyIdResult = openPgpServiceKeyIdExtractor.returnKeyIdsFromIntent(intent, false,
|
||||||
@@ -211,10 +206,10 @@ public class OpenPgpServiceKeyIdExtractorTest {
|
|||||||
.thenReturn(resultCursor);
|
.thenReturn(resultCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupContentResolverResult(String[] userIds, Long[] resultKeyIds, int[] verified) {
|
private void setupContentResolverResult(String[] userIds, Long[] resultKeyIds, int[] verified, int[] candidates) {
|
||||||
MatrixCursor resultCursor = new MatrixCursor(OpenPgpServiceKeyIdExtractor.PROJECTION_MAIL_STATUS);
|
MatrixCursor resultCursor = new MatrixCursor(OpenPgpServiceKeyIdExtractor.PROJECTION_MAIL_STATUS);
|
||||||
for (int i = 0; i < userIds.length; i++) {
|
for (int i = 0; i < userIds.length; i++) {
|
||||||
resultCursor.addRow(new Object[] { userIds[i], resultKeyIds[i], verified[i] });
|
resultCursor.addRow(new Object[] { userIds[i], resultKeyIds[i], verified[i], candidates[i], null, null, null });
|
||||||
}
|
}
|
||||||
|
|
||||||
when(contentResolver.query(
|
when(contentResolver.query(
|
||||||
@@ -222,12 +217,16 @@ public class OpenPgpServiceKeyIdExtractorTest {
|
|||||||
.thenReturn(resultCursor);
|
.thenReturn(resultCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupPendingIntentFactoryResult(PendingIntent pendingIntent) {
|
private void setupSelectPubkeyPendingIntentFactoryResult(PendingIntent pendingIntent) {
|
||||||
when(apiPendingIntentFactory.createSelectPublicKeyPendingIntent(
|
when(apiPendingIntentFactory.createSelectPublicKeyPendingIntent(
|
||||||
any(Intent.class), any(long[].class), any(ArrayList.class), any(ArrayList.class), any(Boolean.class)))
|
any(Intent.class), any(long[].class), any(ArrayList.class), any(ArrayList.class), any(Boolean.class)))
|
||||||
.thenReturn(pendingIntent);
|
.thenReturn(pendingIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupDeduplicatePendingIntentFactoryResult(PendingIntent pendingIntent) {
|
||||||
|
when(apiPendingIntentFactory.createDeduplicatePendingIntent(
|
||||||
|
any(String.class), any(Intent.class), any(ArrayList.class))).thenReturn(pendingIntent);
|
||||||
|
}
|
||||||
|
|
||||||
private static void assertArrayEqualsSorted(long[] a, long[] b) {
|
private static void assertArrayEqualsSorted(long[] a, long[] b) {
|
||||||
long[] tmpA = Arrays.copyOf(a, a.length);
|
long[] tmpA = Arrays.copyOf(a, a.length);
|
||||||
|
|||||||
Reference in New Issue
Block a user