bring email status back for legacy support

This commit is contained in:
Vincent Breitmoser
2017-06-27 11:47:49 +02:00
parent a5d2a77f8f
commit 0d5cb208e3
4 changed files with 153 additions and 162 deletions

View File

@@ -22,7 +22,6 @@ import android.net.Uri;
import android.provider.BaseColumns; import android.provider.BaseColumns;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAutocryptPeerColumns;
public class KeychainExternalContract { public class KeychainExternalContract {
@@ -33,10 +32,26 @@ 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_PEERS = "autocrypt_peers"; public static final String BASE_AUTOCRYPT_STATUS = "autocrypt_status";
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 class EmailStatus implements BaseColumns { public static class EmailStatus implements BaseColumns {
public static final String EMAIL_ADDRESS = "email_address";
public static final String USER_ID = "user_id";
public static final String USER_ID_STATUS = "email_status";
public static final String MASTER_KEY_ID = "master_key_id";
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.email_status";
}
public static class AutocryptStatus implements BaseColumns {
public static final String ADDRESS = "address"; public static final String ADDRESS = "address";
public static final String UID_ADDRESS = "uid_address"; public static final String UID_ADDRESS = "uid_address";
@@ -50,35 +65,18 @@ public class KeychainExternalContract {
public static final String AUTOCRYPT_LAST_SEEN = "autocrypt_last_seen"; 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 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_RESET = 0;
public static final int AUTOCRYPT_PEER_GOSSIP = 1; public static final int AUTOCRYPT_PEER_GOSSIP = 1;
public static final int AUTOCRYPT_PEER_AVAILABLE = 2; public static final int AUTOCRYPT_PEER_AVAILABLE = 2;
public static final int AUTOCRYPT_PEER_MUTUAL = 3; 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_AUTOCRYPT_STATUS).build();
public static final String CONTENT_TYPE = public static final String CONTENT_TYPE =
"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 ApiAutocryptPeer implements ApiAutocryptPeerColumns, BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_EXTERNAL.buildUpon()
.appendPath(BASE_AUTOCRYPT_PEERS).build();
public static Uri buildByPackageNameUri(String packageName) {
return CONTENT_URI.buildUpon().appendEncodedPath(packageName).build();
}
public static Uri buildByPackageNameAndTrustIdUri(String packageName, String autocryptPeer) {
return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendEncodedPath(autocryptPeer).build();
}
}
private KeychainExternalContract() { private KeychainExternalContract() {
} }
} }

View File

@@ -19,6 +19,12 @@
package org.sufficientlysecure.keychain.provider; package org.sufficientlysecure.keychain.provider;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import android.content.ContentProvider; import android.content.ContentProvider;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.UriMatcher; import android.content.UriMatcher;
@@ -46,11 +52,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserPacketsColu
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
public class KeychainProvider extends ContentProvider { public class KeychainProvider extends ContentProvider {
private static final int KEY_RINGS_UNIFIED = 101; private static final int KEY_RINGS_UNIFIED = 101;

View File

@@ -17,10 +17,12 @@
package org.sufficientlysecure.keychain.remote; package org.sufficientlysecure.keychain.remote;
import java.security.AccessControlException; 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;
@@ -40,6 +42,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.ApiDataAccessObject; import org.sufficientlysecure.keychain.provider.ApiDataAccessObject;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAutocryptPeer;
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
@@ -47,15 +50,17 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
import org.sufficientlysecure.keychain.provider.KeychainDatabase; 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.AutocryptStatus;
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;
public class KeychainExternalProvider extends ContentProvider implements SimpleContentResolverInterface { public class KeychainExternalProvider extends ContentProvider implements SimpleContentResolverInterface {
private static final int EMAIL_STATUS = 101; private static final int EMAIL_STATUS = 101;
private static final int EMAIL_STATUS_INTERNAL = 102;
private static final int AUTOCRYPT_PEER = 201; private static final int AUTOCRYPT_STATUS = 201;
private static final int AUTOCRYPT_STATUS_INTERNAL = 202;
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;
@@ -76,7 +81,7 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
String authority = KeychainExternalContract.CONTENT_AUTHORITY_EXTERNAL; String authority = KeychainExternalContract.CONTENT_AUTHORITY_EXTERNAL;
/** /*
* list email_status * list email_status
* *
* <pre> * <pre>
@@ -84,9 +89,9 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
* </pre> * </pre>
*/ */
matcher.addURI(authority, KeychainExternalContract.BASE_EMAIL_STATUS, EMAIL_STATUS); matcher.addURI(authority, KeychainExternalContract.BASE_EMAIL_STATUS, EMAIL_STATUS);
matcher.addURI(authority, KeychainExternalContract.BASE_EMAIL_STATUS + "/*", EMAIL_STATUS_INTERNAL);
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_PEERS + "/*", AUTOCRYPT_PEER); matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS, AUTOCRYPT_STATUS);
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS + "/*", AUTOCRYPT_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);
@@ -146,16 +151,8 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
String callingPackageName = mApiPermissionHelper.getCurrentCallingPackage(); String callingPackageName = mApiPermissionHelper.getCurrentCallingPackage();
switch (match) { switch (match) {
case EMAIL_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 EMAIL_STATUS: { case EMAIL_STATUS: {
boolean callerIsAllowed = (match == EMAIL_STATUS_INTERNAL) || mApiPermissionHelper.isAllowedIgnoreErrors(); boolean callerIsAllowed = mApiPermissionHelper.isAllowedIgnoreErrors();
if (!callerIsAllowed) { if (!callerIsAllowed) {
throw new AccessControlException("An application must register before use of KeychainExternalProvider!"); throw new AccessControlException("An application must register before use of KeychainExternalProvider!");
} }
@@ -169,38 +166,113 @@ 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.ADDRESS, // this is actually the queried address projectionMap.put(EmailStatus.EMAIL_ADDRESS, // this is actually the queried address
TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES + " AS " + EmailStatus.ADDRESS); TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES + " AS " + EmailStatus.EMAIL_ADDRESS);
projectionMap.put(EmailStatus.USER_ID,
projectionMap.put(EmailStatus.UID_ADDRESS, Tables.USER_PACKETS + "." + UserPackets.USER_ID + " AS " + EmailStatus.USER_ID);
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.UID_KEY_STATUS, "CASE ( MIN (certs_user_id." + Certs.VERIFIED + " ) ) " projectionMap.put(EmailStatus.USER_ID_STATUS, "CASE ( MIN (" + 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 " + EmailStatus.KEY_STATUS_UNVERIFIED + " WHEN " + Certs.VERIFIED_SELF + " THEN " + KeychainExternalContract.KEY_STATUS_UNVERIFIED
+ " WHEN " + Certs.VERIFIED_SECRET + " THEN " + EmailStatus.KEY_STATUS_VERIFIED + " WHEN " + Certs.VERIFIED_SECRET + " THEN " + KeychainExternalContract.KEY_STATUS_VERIFIED
+ " WHEN NULL THEN NULL" + " WHEN NULL THEN " + KeychainExternalContract.KEY_STATUS_UNVERIFIED
+ " END AS " + EmailStatus.UID_KEY_STATUS); + " END AS " + EmailStatus.USER_ID_STATUS);
projectionMap.put(EmailStatus.UID_MASTER_KEY_ID, projectionMap.put(EmailStatus.USER_ID, Tables.USER_PACKETS + "." + UserPackets.USER_ID + " AS " + EmailStatus.USER_ID);
Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " AS " + EmailStatus.UID_MASTER_KEY_ID); projectionMap.put(EmailStatus.MASTER_KEY_ID,
projectionMap.put(EmailStatus.UID_CANDIDATES, Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " AS " + EmailStatus.MASTER_KEY_ID);
"COUNT(DISTINCT " + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + qb.setProjectionMap(projectionMap);
") AS " + EmailStatus.UID_CANDIDATES);
projectionMap.put(EmailStatus.AUTOCRYPT_KEY_STATUS, "CASE ( MIN (certs_autocrypt_peer." + Certs.VERIFIED + " ) ) " if (projection == null) {
throw new IllegalArgumentException("Please provide a projection!");
}
qb.setTables(
TEMP_TABLE_QUERIED_ADDRESSES
+ " LEFT JOIN " + Tables.USER_PACKETS + " ON ("
+ 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 + " ON ("
+ Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = " + Tables.CERTS + "." + Certs.MASTER_KEY_ID
+ " AND " + Tables.USER_PACKETS + "." + UserPackets.RANK + " = " + Tables.CERTS + "." + 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;
}
// 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;
}
// uri to watch is all /key_rings/
uri = KeyRings.CONTENT_URI;
break;
}
case AUTOCRYPT_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_STATUS: {
boolean callerIsAllowed = (match == AUTOCRYPT_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(AutocryptStatus._ID, "email AS _id");
projectionMap.put(AutocryptStatus.ADDRESS, // this is actually the queried address
TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES + " AS " + AutocryptStatus.ADDRESS);
projectionMap.put(AutocryptStatus.UID_ADDRESS,
Tables.USER_PACKETS + "." + UserPackets.USER_ID + " AS " + AutocryptStatus.UID_ADDRESS);
// we take the minimum (>0) here, where "1" is "verified by known secret key", "2" is "self-certified"
projectionMap.put(AutocryptStatus.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 " + EmailStatus.KEY_STATUS_UNVERIFIED + " WHEN " + Certs.VERIFIED_SELF + " THEN " + KeychainExternalContract.KEY_STATUS_UNVERIFIED
+ " WHEN " + Certs.VERIFIED_SECRET + " THEN " + EmailStatus.KEY_STATUS_VERIFIED + " WHEN " + Certs.VERIFIED_SECRET + " THEN " + KeychainExternalContract.KEY_STATUS_VERIFIED
+ " WHEN NULL THEN NULL" + " WHEN NULL THEN NULL"
+ " END AS " + EmailStatus.AUTOCRYPT_KEY_STATUS); + " END AS " + AutocryptStatus.UID_KEY_STATUS);
projectionMap.put(EmailStatus.AUTOCRYPT_MASTER_KEY_ID, projectionMap.put(AutocryptStatus.UID_MASTER_KEY_ID,
Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.MASTER_KEY_ID + " AS " + EmailStatus.AUTOCRYPT_MASTER_KEY_ID); Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " AS " + AutocryptStatus.UID_MASTER_KEY_ID);
projectionMap.put(EmailStatus.AUTOCRYPT_PEER_STATE, Tables.API_AUTOCRYPT_PEERS + "." + projectionMap.put(AutocryptStatus.UID_CANDIDATES,
ApiAutocryptPeer.STATE + " AS " + EmailStatus.AUTOCRYPT_LAST_SEEN_KEY); "COUNT(DISTINCT " + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID +
projectionMap.put(EmailStatus.AUTOCRYPT_LAST_SEEN, Tables.API_AUTOCRYPT_PEERS + "." + ") AS " + AutocryptStatus.UID_CANDIDATES);
ApiAutocryptPeer.LAST_SEEN + " AS " + EmailStatus.AUTOCRYPT_LAST_SEEN);
projectionMap.put(EmailStatus.AUTOCRYPT_LAST_SEEN_KEY, Tables.API_AUTOCRYPT_PEERS + "." + projectionMap.put(AutocryptStatus.AUTOCRYPT_KEY_STATUS, "CASE ( MIN (certs_autocrypt_peer." + Certs.VERIFIED + " ) ) "
ApiAutocryptPeer.LAST_SEEN_KEY + " AS " + EmailStatus.AUTOCRYPT_LAST_SEEN_KEY); // 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 " + AutocryptStatus.AUTOCRYPT_KEY_STATUS);
projectionMap.put(AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID,
Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.MASTER_KEY_ID + " AS " + AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID);
projectionMap.put(AutocryptStatus.AUTOCRYPT_PEER_STATE, Tables.API_AUTOCRYPT_PEERS + "." +
ApiAutocryptPeer.STATE + " AS " + AutocryptStatus.AUTOCRYPT_LAST_SEEN_KEY);
projectionMap.put(AutocryptStatus.AUTOCRYPT_LAST_SEEN, Tables.API_AUTOCRYPT_PEERS + "." +
ApiAutocryptPeer.LAST_SEEN + " AS " + AutocryptStatus.AUTOCRYPT_LAST_SEEN);
projectionMap.put(AutocryptStatus.AUTOCRYPT_LAST_SEEN_KEY, Tables.API_AUTOCRYPT_PEERS + "." +
ApiAutocryptPeer.LAST_SEEN_KEY + " AS " + AutocryptStatus.AUTOCRYPT_LAST_SEEN_KEY);
qb.setProjectionMap(projectionMap); qb.setProjectionMap(projectionMap);
if (projection == null) { if (projection == null) {
@@ -237,7 +309,7 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
+ ")) OR " + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " IS NULL"); + ")) OR " + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " IS NULL");
if (TextUtils.isEmpty(sortOrder)) { if (TextUtils.isEmpty(sortOrder)) {
sortOrder = EmailStatus.ADDRESS; sortOrder = AutocryptStatus.ADDRESS;
} }
// uri to watch is all /key_rings/ // uri to watch is all /key_rings/
@@ -245,36 +317,6 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
break; break;
} }
case AUTOCRYPT_PEER: {
boolean callerIsAllowed = mApiPermissionHelper.isAllowedIgnoreErrors();
if (!callerIsAllowed) {
throw new AccessControlException("An application must register before use of KeychainExternalProvider!");
}
if (projection == null) {
throw new IllegalArgumentException("Please provide a projection!");
}
HashMap<String, String> projectionMap = new HashMap<>();
projectionMap.put(ApiAutocryptPeer._ID, "oid AS " + ApiAutocryptPeer._ID);
projectionMap.put(ApiAutocryptPeer.IDENTIFIER, ApiAutocryptPeer.IDENTIFIER);
projectionMap.put(ApiAutocryptPeer.MASTER_KEY_ID, ApiAutocryptPeer.MASTER_KEY_ID);
projectionMap.put(ApiAutocryptPeer.LAST_SEEN, ApiAutocryptPeer.LAST_SEEN);
projectionMap.put(ApiAutocryptPeer.LAST_SEEN_KEY, ApiAutocryptPeer.LAST_SEEN_KEY);
qb.setProjectionMap(projectionMap);
qb.setTables(Tables.API_AUTOCRYPT_PEERS);
// allow access to columns of the calling package exclusively!
qb.appendWhere(Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.PACKAGE_NAME +
" = " + mApiPermissionHelper.getCurrentCallingPackage());
qb.appendWhere(Tables.API_AUTOCRYPT_PEERS + "." + ApiAutocryptPeer.IDENTIFIER + " = ");
qb.appendWhereEscapeString(uri.getLastPathSegment());
break;
}
case API_APPS_BY_PACKAGE_NAME: { case API_APPS_BY_PACKAGE_NAME: {
String requestedPackageName = uri.getLastPathSegment(); String requestedPackageName = uri.getLastPathSegment();
checkIfPackageBelongsToCaller(getContext(), requestedPackageName); checkIfPackageBelongsToCaller(getContext(), requestedPackageName);
@@ -336,64 +378,12 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
@Override @Override
public Uri insert(@NonNull Uri uri, ContentValues values) { public Uri insert(@NonNull Uri uri, ContentValues values) {
Log.v(Constants.TAG, "insert(uri=" + uri + ")"); throw new UnsupportedOperationException();
int match = mUriMatcher.match(uri);
if (match != AUTOCRYPT_PEER) {
throw new UnsupportedOperationException();
}
boolean callerIsAllowed = mApiPermissionHelper.isAllowedIgnoreErrors();
if (!callerIsAllowed) {
throw new AccessControlException("An application must register before use of KeychainExternalProvider!");
}
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();
actualValues.put(ApiAutocryptPeer.PACKAGE_NAME, mApiPermissionHelper.getCurrentCallingPackage());
actualValues.put(ApiAutocryptPeer.IDENTIFIER, uri.getLastPathSegment());
actualValues.put(ApiAutocryptPeer.MASTER_KEY_ID, masterKeyId);
actualValues.put(ApiAutocryptPeer.LAST_SEEN, new Date().getTime() / 1000);
SQLiteDatabase db = getDb().getWritableDatabase();
try {
db.insert(Tables.API_AUTOCRYPT_PEERS, null, actualValues);
return uri;
} finally {
db.close();
}
} }
@Override @Override
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) { public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
Log.v(Constants.TAG, "delete(uri=" + uri + ")"); throw new UnsupportedOperationException();
int match = mUriMatcher.match(uri);
if (match != AUTOCRYPT_PEER || selection != null || selectionArgs != null) {
throw new UnsupportedOperationException();
}
boolean callerIsAllowed = mApiPermissionHelper.isAllowedIgnoreErrors();
if (!callerIsAllowed) {
throw new AccessControlException("An application must register before use of KeychainExternalProvider!");
}
String actualSelection = ApiAutocryptPeer.PACKAGE_NAME + " = ? AND " + ApiAutocryptPeer.IDENTIFIER + " = ?";
String[] actualSelectionArgs = new String[] {
mApiPermissionHelper.getCurrentCallingPackage(),
uri.getLastPathSegment()
};
SQLiteDatabase db = getDb().getWritableDatabase();
try {
return db.delete(Tables.API_AUTOCRYPT_PEERS, actualSelection, actualSelectionArgs);
} finally {
db.close();
}
} }
@Override @Override

View File

@@ -16,6 +16,8 @@ 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.KeychainContract.ApiAutocryptPeer; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAutocryptPeer;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptStatus;
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;
@@ -24,13 +26,13 @@ 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.ADDRESS, AutocryptStatus.ADDRESS,
EmailStatus.UID_MASTER_KEY_ID, AutocryptStatus.UID_MASTER_KEY_ID,
EmailStatus.UID_KEY_STATUS, AutocryptStatus.UID_KEY_STATUS,
EmailStatus.UID_CANDIDATES, AutocryptStatus.UID_CANDIDATES,
EmailStatus.AUTOCRYPT_MASTER_KEY_ID, AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID,
EmailStatus.AUTOCRYPT_KEY_STATUS, AutocryptStatus.AUTOCRYPT_KEY_STATUS,
EmailStatus.AUTOCRYPT_PEER_STATE AutocryptStatus.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;
@@ -108,7 +110,7 @@ class OpenPgpServiceKeyIdExtractor {
if (addressQueryResult.autocryptMasterKeyId != null) { if (addressQueryResult.autocryptMasterKeyId != null) {
keyIds.add(addressQueryResult.autocryptMasterKeyId); keyIds.add(addressQueryResult.autocryptMasterKeyId);
if (addressQueryResult.autocryptKeyStatus != EmailStatus.KEY_STATUS_VERIFIED) { if (addressQueryResult.autocryptKeyStatus != KeychainExternalContract.KEY_STATUS_VERIFIED) {
anyKeyNotVerified = true; anyKeyNotVerified = true;
} }
@@ -129,7 +131,7 @@ class OpenPgpServiceKeyIdExtractor {
duplicateEmails.add(queriedAddress); duplicateEmails.add(queriedAddress);
} }
if (addressQueryResult.uidKeyStatus != EmailStatus.KEY_STATUS_VERIFIED) { if (addressQueryResult.uidKeyStatus != KeychainExternalContract.KEY_STATUS_VERIFIED) {
anyKeyNotVerified = true; anyKeyNotVerified = true;
} }
@@ -169,7 +171,7 @@ class OpenPgpServiceKeyIdExtractor {
@NonNull @NonNull
private HashMap<String, AddressQueryResult> getStatusMapForQueriedAddresses(String[] encryptionUserIds, String callingPackageName) { private HashMap<String, AddressQueryResult> getStatusMapForQueriedAddresses(String[] encryptionUserIds, String callingPackageName) {
HashMap<String,AddressQueryResult> keyRows = new HashMap<>(); HashMap<String,AddressQueryResult> keyRows = new HashMap<>();
Uri queryUri = EmailStatus.CONTENT_URI.buildUpon().appendPath(callingPackageName).build(); Uri queryUri = AutocryptStatus.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) {
throw new IllegalStateException("Internal error, received null cursor!"); throw new IllegalStateException("Internal error, received null cursor!");