Fix up logic to match Autocrypt 1.0
This commit is contained in:
@@ -24,13 +24,44 @@ import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.DatabaseUtils;
|
||||
import android.net.Uri;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAutocryptPeer;
|
||||
|
||||
|
||||
public class AutocryptPeerDataAccessObject {
|
||||
private final SimpleContentResolverInterface mQueryInterface;
|
||||
private static final long AUTOCRYPT_DISCOURAGE_THRESHOLD_MILLIS = 35 * DateUtils.DAY_IN_MILLIS;
|
||||
|
||||
private static final String[] PROJECTION_AUTOCRYPT_QUERY = {
|
||||
ApiAutocryptPeer.LAST_SEEN,
|
||||
ApiAutocryptPeer.MASTER_KEY_ID,
|
||||
ApiAutocryptPeer.LAST_SEEN_KEY,
|
||||
ApiAutocryptPeer.IS_MUTUAL,
|
||||
ApiAutocryptPeer.KEY_IS_REVOKED,
|
||||
ApiAutocryptPeer.KEY_IS_EXPIRED,
|
||||
ApiAutocryptPeer.KEY_IS_VERIFIED,
|
||||
ApiAutocryptPeer.GOSSIP_MASTER_KEY_ID,
|
||||
ApiAutocryptPeer.GOSSIP_LAST_SEEN_KEY,
|
||||
ApiAutocryptPeer.GOSSIP_KEY_IS_REVOKED,
|
||||
ApiAutocryptPeer.GOSSIP_KEY_IS_EXPIRED,
|
||||
ApiAutocryptPeer.GOSSIP_KEY_IS_VERIFIED,
|
||||
};
|
||||
private static final int INDEX_LAST_SEEN = 0;
|
||||
private static final int INDEX_MASTER_KEY_ID = 1;
|
||||
private static final int INDEX_LAST_SEEN_KEY = 2;
|
||||
private static final int INDEX_STATE = 3;
|
||||
private static final int INDEX_KEY_IS_REVOKED = 4;
|
||||
private static final int INDEX_KEY_IS_EXPIRED = 5;
|
||||
private static final int INDEX_KEY_IS_VERIFIED = 6;
|
||||
private static final int INDEX_GOSSIP_MASTER_KEY_ID = 7;
|
||||
private static final int INDEX_GOSSIP_LAST_SEEN_KEY = 8;
|
||||
private static final int INDEX_GOSSIP_KEY_IS_REVOKED = 9;
|
||||
private static final int INDEX_GOSSIP_KEY_IS_EXPIRED = 10;
|
||||
private static final int INDEX_GOSSIP_KEY_IS_VERIFIED = 11;
|
||||
|
||||
private final SimpleContentResolverInterface queryInterface;
|
||||
private final String packageName;
|
||||
|
||||
|
||||
@@ -38,7 +69,7 @@ public class AutocryptPeerDataAccessObject {
|
||||
this.packageName = packageName;
|
||||
|
||||
final ContentResolver contentResolver = context.getContentResolver();
|
||||
mQueryInterface = new SimpleContentResolverInterface() {
|
||||
queryInterface = new SimpleContentResolverInterface() {
|
||||
@Override
|
||||
public Cursor query(Uri contentUri, String[] projection, String selection, String[] selectionArgs,
|
||||
String sortOrder) {
|
||||
@@ -63,12 +94,12 @@ public class AutocryptPeerDataAccessObject {
|
||||
}
|
||||
|
||||
public AutocryptPeerDataAccessObject(SimpleContentResolverInterface queryInterface, String packageName) {
|
||||
mQueryInterface = queryInterface;
|
||||
this.queryInterface = queryInterface;
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
public Long getMasterKeyIdForAutocryptPeer(String autocryptId) {
|
||||
Cursor cursor = mQueryInterface.query(
|
||||
Cursor cursor = queryInterface.query(
|
||||
ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), null, null, null, null);
|
||||
|
||||
try {
|
||||
@@ -86,7 +117,7 @@ public class AutocryptPeerDataAccessObject {
|
||||
}
|
||||
|
||||
public Date getLastSeen(String autocryptId) {
|
||||
Cursor cursor = mQueryInterface.query(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId),
|
||||
Cursor cursor = queryInterface.query(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId),
|
||||
null, null, null, null);
|
||||
|
||||
try {
|
||||
@@ -103,7 +134,7 @@ public class AutocryptPeerDataAccessObject {
|
||||
}
|
||||
|
||||
public Date getLastSeenKey(String autocryptId) {
|
||||
Cursor cursor = mQueryInterface.query(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId),
|
||||
Cursor cursor = queryInterface.query(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId),
|
||||
null, null, null, null);
|
||||
|
||||
try {
|
||||
@@ -119,38 +150,112 @@ public class AutocryptPeerDataAccessObject {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void updateToResetState(String autocryptId, Date effectiveDate) {
|
||||
updateAutocryptState(autocryptId, effectiveDate, null, ApiAutocryptPeer.RESET);
|
||||
public void updateLastSeen(String autocryptId, Date date) {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(ApiAutocryptPeer.LAST_SEEN, date.getTime());
|
||||
queryInterface
|
||||
.update(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), cv, null, null);
|
||||
}
|
||||
|
||||
public void updateToSelectedState(String autocryptId, long masterKeyId) {
|
||||
updateAutocryptState(autocryptId, new Date(), masterKeyId, ApiAutocryptPeer.SELECTED);
|
||||
}
|
||||
|
||||
public void updateToGossipState(String autocryptId, Date effectiveDate, long masterKeyId) {
|
||||
updateAutocryptState(autocryptId, effectiveDate, masterKeyId, ApiAutocryptPeer.GOSSIP);
|
||||
}
|
||||
|
||||
public void updateToMutualState(String autocryptId, Date effectiveDate, long masterKeyId) {
|
||||
updateAutocryptState(autocryptId, effectiveDate, masterKeyId, ApiAutocryptPeer.MUTUAL);
|
||||
}
|
||||
|
||||
public void updateToAvailableState(String autocryptId, Date effectiveDate, long masterKeyId) {
|
||||
updateAutocryptState(autocryptId, effectiveDate, masterKeyId, ApiAutocryptPeer.AVAILABLE);
|
||||
}
|
||||
|
||||
private void updateAutocryptState(String autocryptId, Date date, Long masterKeyId, int status) {
|
||||
public void updateKey(String autocryptId, Date effectiveDate, long masterKeyId, boolean isMutual) {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(ApiAutocryptPeer.MASTER_KEY_ID, masterKeyId);
|
||||
cv.put(ApiAutocryptPeer.LAST_SEEN, date.getTime());
|
||||
if (masterKeyId != null) {
|
||||
cv.put(ApiAutocryptPeer.LAST_SEEN_KEY, masterKeyId);
|
||||
}
|
||||
cv.put(ApiAutocryptPeer.STATE, status);
|
||||
mQueryInterface.update(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), cv, null, null);
|
||||
cv.put(ApiAutocryptPeer.LAST_SEEN_KEY, effectiveDate.getTime());
|
||||
cv.put(ApiAutocryptPeer.IS_MUTUAL, isMutual ? 1 : 0);
|
||||
queryInterface
|
||||
.update(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), cv, null, null);
|
||||
}
|
||||
|
||||
public void updateKeyGossip(String autocryptId, Date effectiveDate, long masterKeyId) {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(ApiAutocryptPeer.GOSSIP_MASTER_KEY_ID, masterKeyId);
|
||||
cv.put(ApiAutocryptPeer.GOSSIP_LAST_SEEN_KEY, effectiveDate.getTime());
|
||||
queryInterface
|
||||
.update(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), cv, null, null);
|
||||
}
|
||||
|
||||
public void delete(String autocryptId) {
|
||||
mQueryInterface.delete(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), null, null);
|
||||
queryInterface.delete(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), null, null);
|
||||
}
|
||||
|
||||
public AutocryptPeerStateResult getAutocryptState(String autocryptId) {
|
||||
/*
|
||||
Determine if encryption is possible
|
||||
If there is no peers[to-addr], then set ui-recommendation to disable, and terminate.
|
||||
|
||||
For the purposes of the rest of this recommendation, if either public_key or gossip_key is revoked, expired, or otherwise known to be unusable for encryption, then treat that key as though it were null (not present).
|
||||
|
||||
If both public_key and gossip_key are null, then set ui-recommendation to disable and terminate.
|
||||
|
||||
Otherwise, we derive the recommendation using a two-phase algorithm. The first phase computes the preliminary-recommendation.
|
||||
|
||||
Preliminary Recommendation
|
||||
If public_key is null, then set target-keys[to-addr] to gossip_key and set preliminary-recommendation to discourage and skip to the Deciding to Encrypt by Default.
|
||||
|
||||
Otherwise, set target-keys[to-addr] to public_key.
|
||||
|
||||
If autocrypt_timestamp is more than 35 days older than last_seen, set preliminary-recommendation to discourage.
|
||||
|
||||
Otherwise, set preliminary-recommendation to available.
|
||||
*/
|
||||
|
||||
Cursor cursor = queryInterface.query(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId),
|
||||
PROJECTION_AUTOCRYPT_QUERY, null, null, null);
|
||||
try {
|
||||
if (!cursor.moveToFirst()) {
|
||||
return new AutocryptPeerStateResult(AutocryptState.DISABLE, null, false);
|
||||
}
|
||||
|
||||
boolean hasKey = !cursor.isNull(INDEX_MASTER_KEY_ID);
|
||||
boolean isRevoked = cursor.getInt(INDEX_KEY_IS_REVOKED) != 0;
|
||||
boolean isExpired = cursor.getInt(INDEX_KEY_IS_EXPIRED) != 0;
|
||||
if (hasKey && !isRevoked && !isExpired) {
|
||||
long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
|
||||
long lastSeen = cursor.getLong(INDEX_LAST_SEEN);
|
||||
long lastSeenKey = cursor.getLong(INDEX_LAST_SEEN_KEY);
|
||||
boolean isVerified = cursor.getInt(INDEX_KEY_IS_VERIFIED) != 0;
|
||||
if (lastSeenKey < (lastSeen - AUTOCRYPT_DISCOURAGE_THRESHOLD_MILLIS)) {
|
||||
return new AutocryptPeerStateResult(AutocryptState.DISCOURAGED_OLD, masterKeyId, isVerified);
|
||||
}
|
||||
|
||||
boolean isMutual = cursor.getInt(INDEX_STATE) != 0;
|
||||
if (isMutual) {
|
||||
return new AutocryptPeerStateResult(AutocryptState.MUTUAL, masterKeyId, isVerified);
|
||||
} else {
|
||||
return new AutocryptPeerStateResult(AutocryptState.AVAILABLE, masterKeyId, isVerified);
|
||||
}
|
||||
}
|
||||
|
||||
boolean gossipHasKey = !cursor.isNull(INDEX_GOSSIP_MASTER_KEY_ID);
|
||||
boolean gossipIsRevoked = cursor.getInt(INDEX_GOSSIP_KEY_IS_REVOKED) != 0;
|
||||
boolean gossipIsExpired = cursor.getInt(INDEX_GOSSIP_KEY_IS_EXPIRED) != 0;
|
||||
boolean isVerified = cursor.getInt(INDEX_GOSSIP_KEY_IS_VERIFIED) != 0;
|
||||
if (gossipHasKey && !gossipIsRevoked && !gossipIsExpired) {
|
||||
System.err.println("xx");
|
||||
long masterKeyId = cursor.getLong(INDEX_GOSSIP_MASTER_KEY_ID);
|
||||
return new AutocryptPeerStateResult(AutocryptState.DISCOURAGED_GOSSIP, masterKeyId, isVerified);
|
||||
}
|
||||
|
||||
return new AutocryptPeerStateResult(AutocryptState.DISABLE, null, false);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AutocryptPeerStateResult {
|
||||
public final Long masterKeyId;
|
||||
public final AutocryptState autocryptState;
|
||||
public final boolean isVerified;
|
||||
|
||||
AutocryptPeerStateResult(AutocryptState autocryptState, Long masterKeyId, boolean isVerified) {
|
||||
this.autocryptState = autocryptState;
|
||||
this.masterKeyId = masterKeyId;
|
||||
this.isVerified = isVerified;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum AutocryptState {
|
||||
DISABLE, DISCOURAGED_OLD, DISCOURAGED_GOSSIP, AVAILABLE, MUTUAL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,9 +103,13 @@ public class KeychainContract {
|
||||
String PACKAGE_NAME = "package_name";
|
||||
String IDENTIFIER = "identifier";
|
||||
String LAST_SEEN = "last_updated";
|
||||
String LAST_SEEN_KEY = "last_seen_key";
|
||||
String STATE = "state";
|
||||
|
||||
String MASTER_KEY_ID = "master_key_id";
|
||||
String LAST_SEEN_KEY = "last_seen_key";
|
||||
String IS_MUTUAL = "is_mutual";
|
||||
|
||||
String GOSSIP_MASTER_KEY_ID = "gossip_master_key_id";
|
||||
String GOSSIP_LAST_SEEN_KEY = "gossip_last_seen_key";
|
||||
}
|
||||
|
||||
public static final String CONTENT_AUTHORITY = Constants.PROVIDER_AUTHORITY;
|
||||
@@ -371,12 +375,12 @@ public class KeychainContract {
|
||||
public static class ApiAutocryptPeer implements ApiAutocryptPeerColumns, BaseColumns {
|
||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
||||
.appendPath(BASE_AUTOCRYPT_PEERS).build();
|
||||
|
||||
public static final int RESET = 0;
|
||||
public static final int GOSSIP = 1;
|
||||
public static final int SELECTED = 2;
|
||||
public static final int AVAILABLE = 3;
|
||||
public static final int MUTUAL = 4;
|
||||
public static final String KEY_IS_REVOKED = "key_is_revoked";
|
||||
public static final String KEY_IS_EXPIRED = "key_is_expired";
|
||||
public static final String KEY_IS_VERIFIED = "key_is_verified";
|
||||
public static final String GOSSIP_KEY_IS_REVOKED = "gossip_key_is_revoked";
|
||||
public static final String GOSSIP_KEY_IS_EXPIRED = "gossip_key_is_expired";
|
||||
public static final String GOSSIP_KEY_IS_VERIFIED = "gossip_key_is_verified";
|
||||
|
||||
public static Uri buildByKeyUri(Uri uri) {
|
||||
return CONTENT_URI.buildUpon().appendPath(PATH_BY_KEY_ID).appendPath(uri.getPathSegments().get(1)).build();
|
||||
|
||||
@@ -54,7 +54,7 @@ import timber.log.Timber;
|
||||
*/
|
||||
public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
private static final String DATABASE_NAME = "openkeychain.db";
|
||||
private static final int DATABASE_VERSION = 24;
|
||||
private static final int DATABASE_VERSION = 25;
|
||||
private Context mContext;
|
||||
|
||||
public interface Tables {
|
||||
@@ -173,10 +173,12 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
"CREATE TABLE IF NOT EXISTS " + Tables.API_AUTOCRYPT_PEERS + " ("
|
||||
+ ApiAutocryptPeerColumns.PACKAGE_NAME + " TEXT NOT NULL, "
|
||||
+ ApiAutocryptPeerColumns.IDENTIFIER + " TEXT NOT NULL, "
|
||||
+ ApiAutocryptPeerColumns.LAST_SEEN + " INTEGER NOT NULL, "
|
||||
+ ApiAutocryptPeerColumns.LAST_SEEN_KEY + " INTEGER NOT NULL, "
|
||||
+ ApiAutocryptPeerColumns.STATE + " INTEGER NOT NULL, "
|
||||
+ ApiAutocryptPeerColumns.LAST_SEEN + " INTEGER, "
|
||||
+ ApiAutocryptPeerColumns.LAST_SEEN_KEY + " INTEGER NULL, "
|
||||
+ ApiAutocryptPeerColumns.IS_MUTUAL + " INTEGER NULL, "
|
||||
+ ApiAutocryptPeerColumns.MASTER_KEY_ID + " INTEGER NULL, "
|
||||
+ ApiAutocryptPeerColumns.GOSSIP_MASTER_KEY_ID + " INTEGER NULL, "
|
||||
+ ApiAutocryptPeerColumns.GOSSIP_LAST_SEEN_KEY + " INTEGER NULL, "
|
||||
+ "PRIMARY KEY(" + ApiAutocryptPeerColumns.PACKAGE_NAME + ", "
|
||||
+ ApiAutocryptPeerColumns.IDENTIFIER + "), "
|
||||
+ "FOREIGN KEY(" + ApiAutocryptPeerColumns.PACKAGE_NAME + ") REFERENCES "
|
||||
@@ -406,6 +408,10 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
||||
+ "PRIMARY KEY(master_key_id, signer_key_id), "
|
||||
+ "FOREIGN KEY(master_key_id) REFERENCES keyrings_public(master_key_id) ON DELETE CASCADE"
|
||||
+ ")");
|
||||
|
||||
case 24:
|
||||
db.execSQL("DROP TABLE api_autocrypt_peers");
|
||||
db.execSQL(CREATE_API_AUTOCRYPT_PEERS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,14 +63,13 @@ public class KeychainExternalContract {
|
||||
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 AUTOCRYPT_PEER_RESET = ApiAutocryptPeer.RESET;
|
||||
public static final int AUTOCRYPT_PEER_GOSSIP = ApiAutocryptPeer.GOSSIP;
|
||||
public static final int AUTOCRYPT_PEER_SELECTED = ApiAutocryptPeer.SELECTED;
|
||||
public static final int AUTOCRYPT_PEER_AVAILABLE = ApiAutocryptPeer.AVAILABLE;
|
||||
public static final int AUTOCRYPT_PEER_MUTUAL = ApiAutocryptPeer.MUTUAL;
|
||||
public static final int AUTOCRYPT_PEER_DISABLED = 0;
|
||||
public static final int AUTOCRYPT_PEER_DISCOURAGED_OLD = 10;
|
||||
public static final int AUTOCRYPT_PEER_GOSSIP = 20;
|
||||
public static final int AUTOCRYPT_PEER_AVAILABLE_EXTERNAL = 30;
|
||||
public static final int AUTOCRYPT_PEER_AVAILABLE = 40;
|
||||
public static final int AUTOCRYPT_PEER_MUTUAL = 50;
|
||||
|
||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_EXTERNAL.buildUpon()
|
||||
.appendPath(BASE_AUTOCRYPT_STATUS).build();
|
||||
|
||||
@@ -721,15 +721,47 @@ public class KeychainProvider extends ContentProvider {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
long unixSeconds = new Date().getTime() / 1000;
|
||||
|
||||
HashMap<String, String> projectionMap = new HashMap<>();
|
||||
projectionMap.put(ApiAutocryptPeer._ID, "oid AS " + ApiAutocryptPeer._ID);
|
||||
projectionMap.put(ApiAutocryptPeer.PACKAGE_NAME, ApiAutocryptPeer.PACKAGE_NAME);
|
||||
projectionMap.put(ApiAutocryptPeer.IDENTIFIER, ApiAutocryptPeer.IDENTIFIER);
|
||||
projectionMap.put(ApiAutocryptPeer.MASTER_KEY_ID, ApiAutocryptPeer.MASTER_KEY_ID);
|
||||
projectionMap.put(ApiAutocryptPeer.PACKAGE_NAME, ApiAutocryptPeer.PACKAGE_NAME);
|
||||
projectionMap.put(ApiAutocryptPeer.LAST_SEEN, ApiAutocryptPeer.LAST_SEEN);
|
||||
projectionMap.put(ApiAutocryptPeer.MASTER_KEY_ID, Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.MASTER_KEY_ID);
|
||||
projectionMap.put(ApiAutocryptPeer.IS_MUTUAL, ApiAutocryptPeer.IS_MUTUAL);
|
||||
projectionMap.put(ApiAutocryptPeer.LAST_SEEN_KEY, ApiAutocryptPeer.LAST_SEEN_KEY);
|
||||
projectionMap.put(ApiAutocryptPeer.GOSSIP_MASTER_KEY_ID, ApiAutocryptPeer.GOSSIP_MASTER_KEY_ID);
|
||||
projectionMap.put(ApiAutocryptPeer.GOSSIP_LAST_SEEN_KEY, ApiAutocryptPeer.GOSSIP_LAST_SEEN_KEY);
|
||||
projectionMap.put(ApiAutocryptPeer.KEY_IS_REVOKED, "ac_key." + Keys.IS_REVOKED + " AS " + ApiAutocryptPeer.KEY_IS_REVOKED);
|
||||
projectionMap.put(ApiAutocryptPeer.KEY_IS_EXPIRED, "(CASE" +
|
||||
" WHEN ac_key." + Keys.EXPIRY + " IS NULL THEN 0" +
|
||||
" WHEN ac_key." + Keys.EXPIRY + " > " + unixSeconds + " THEN 0" +
|
||||
" ELSE 1 END) AS " + ApiAutocryptPeer.KEY_IS_EXPIRED);
|
||||
projectionMap.put(ApiAutocryptPeer.KEY_IS_VERIFIED, "EXISTS (SELECT * FROM " + Tables.CERTS +
|
||||
" WHERE " + Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = " +
|
||||
Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.MASTER_KEY_ID +
|
||||
" AND " + Certs.VERIFIED + " = " + Certs.VERIFIED_SECRET +
|
||||
") AS " + ApiAutocryptPeer.KEY_IS_VERIFIED);
|
||||
projectionMap.put(ApiAutocryptPeer.GOSSIP_KEY_IS_REVOKED,
|
||||
"gossip_key." + Keys.IS_REVOKED + " AS " + ApiAutocryptPeer.GOSSIP_KEY_IS_REVOKED);
|
||||
projectionMap.put(ApiAutocryptPeer.GOSSIP_KEY_IS_EXPIRED, "(CASE" +
|
||||
" WHEN gossip_key." + Keys.EXPIRY + " IS NULL THEN 0" +
|
||||
" WHEN gossip_key." + Keys.EXPIRY + " > " + unixSeconds + " THEN 0" +
|
||||
" ELSE 1 END) AS " + ApiAutocryptPeer.GOSSIP_KEY_IS_EXPIRED);
|
||||
projectionMap.put(ApiAutocryptPeer.GOSSIP_KEY_IS_VERIFIED, "EXISTS (SELECT * FROM " + Tables.CERTS +
|
||||
" WHERE " + Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = " +
|
||||
Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.GOSSIP_MASTER_KEY_ID +
|
||||
" AND " + Certs.VERIFIED + " = " + Certs.VERIFIED_SECRET +
|
||||
") AS " + ApiAutocryptPeer.GOSSIP_KEY_IS_VERIFIED);
|
||||
qb.setProjectionMap(projectionMap);
|
||||
|
||||
qb.setTables(Tables.API_AUTOCRYPT_PEERS);
|
||||
qb.setTables(Tables.API_AUTOCRYPT_PEERS +
|
||||
" LEFT JOIN " + Tables.KEYS + " AS ac_key" +
|
||||
" ON (ac_key." + Keys.MASTER_KEY_ID + " = " + Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.MASTER_KEY_ID + ")" +
|
||||
" LEFT JOIN " + Tables.KEYS + " AS gossip_key" +
|
||||
" ON (gossip_key." + Keys.MASTER_KEY_ID + " = " + ApiAutocryptPeer.GOSSIP_MASTER_KEY_ID + ")"
|
||||
);
|
||||
|
||||
if (match == AUTOCRYPT_PEERS_BY_MASTER_KEY_ID) {
|
||||
long masterKeyId = Long.parseLong(uri.getLastPathSegment());
|
||||
@@ -1084,34 +1116,44 @@ public class KeychainProvider extends ContentProvider {
|
||||
break;
|
||||
}
|
||||
case AUTOCRYPT_PEERS_BY_PACKAGE_NAME_AND_TRUST_ID: {
|
||||
Long masterKeyId = values.getAsLong(ApiAutocryptPeer.MASTER_KEY_ID);
|
||||
if (masterKeyId == null) {
|
||||
throw new IllegalArgumentException("master_key_id must be a non-null value!");
|
||||
}
|
||||
|
||||
ContentValues actualValues = new ContentValues();
|
||||
String packageName = uri.getPathSegments().get(2);
|
||||
actualValues.put(ApiAutocryptPeer.PACKAGE_NAME, packageName);
|
||||
actualValues.put(ApiAutocryptPeer.IDENTIFIER, uri.getLastPathSegment());
|
||||
actualValues.put(ApiAutocryptPeer.MASTER_KEY_ID, masterKeyId);
|
||||
|
||||
Long newLastSeen = values.getAsLong(ApiAutocryptPeer.LAST_SEEN);
|
||||
if (newLastSeen != null) {
|
||||
actualValues.put(ApiAutocryptPeer.LAST_SEEN, newLastSeen);
|
||||
db.replace(Tables.API_AUTOCRYPT_PEERS, null, actualValues);
|
||||
break;
|
||||
}
|
||||
|
||||
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));
|
||||
Long masterKeyId = values.getAsLong(ApiAutocryptPeer.MASTER_KEY_ID);
|
||||
if (masterKeyId != null) {
|
||||
Long lastSeenKey = values.getAsLong(ApiAutocryptPeer.LAST_SEEN_KEY);
|
||||
Long preferEncryptState = values.getAsLong(ApiAutocryptPeer.IS_MUTUAL);
|
||||
|
||||
actualValues.put(ApiAutocryptPeer.MASTER_KEY_ID, masterKeyId);
|
||||
actualValues.put(ApiAutocryptPeer.LAST_SEEN_KEY, lastSeenKey);
|
||||
actualValues.put(ApiAutocryptPeer.IS_MUTUAL, preferEncryptState);
|
||||
|
||||
db.replace(Tables.API_AUTOCRYPT_PEERS, null, actualValues);
|
||||
contentResolver.notifyChange(KeyRings.buildGenericKeyRingUri(masterKeyId), null);
|
||||
break;
|
||||
}
|
||||
|
||||
contentResolver.notifyChange(KeyRings.buildGenericKeyRingUri(masterKeyId), null);
|
||||
Long gossipMasterKeyId = values.getAsLong(ApiAutocryptPeer.GOSSIP_MASTER_KEY_ID);
|
||||
if (gossipMasterKeyId != null) {
|
||||
Long gossipLastSeenKey = values.getAsLong(ApiAutocryptPeer.GOSSIP_LAST_SEEN_KEY);
|
||||
|
||||
actualValues.put(ApiAutocryptPeer.GOSSIP_MASTER_KEY_ID, gossipMasterKeyId);
|
||||
actualValues.put(ApiAutocryptPeer.GOSSIP_LAST_SEEN_KEY, gossipLastSeenKey);
|
||||
|
||||
db.replace(Tables.API_AUTOCRYPT_PEERS, null, actualValues);
|
||||
contentResolver.notifyChange(KeyRings.buildGenericKeyRingUri(gossipMasterKeyId), null);
|
||||
break;
|
||||
}
|
||||
|
||||
db.replace(Tables.API_AUTOCRYPT_PEERS, null, actualValues);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
||||
Reference in New Issue
Block a user