db-overhaul: more work on new provider

specifics:
 - secret keys are preserved when a new public key is inserted
 - started work to give virtual columns a representation in the contract
   class
 - streamline ProviderHelper methods. the getUnifiedData method relies
   on a api level 11 method, not sure yet how to fix/workaround that...
 - many more small things work as they did before
This commit is contained in:
Vincent Breitmoser 2014-04-03 22:49:08 +02:00
parent dedcfd8a72
commit 2620e0bfc8
10 changed files with 207 additions and 262 deletions

View File

@ -96,18 +96,14 @@ public class KeychainContract {
public static final String BASE_API_APPS = "api_apps"; public static final String BASE_API_APPS = "api_apps";
public static final String PATH_ACCOUNTS = "accounts"; public static final String PATH_ACCOUNTS = "accounts";
public static class KeyRings implements KeyRingsColumns, BaseColumns { public static class KeyRings implements BaseColumns, KeysColumns, UserIdsColumns {
public static final String MASTER_KEY_ID = "master_key_id";
public static final String HAS_SECRET = "has_secret";
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_KEY_RINGS).build(); .appendPath(BASE_KEY_RINGS).build();
/**
* Use if multiple items get returned
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring"; public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring";
/**
* Use if a single item is returned
*/
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring";
public static Uri buildUnifiedKeyRingsUri() { public static Uri buildUnifiedKeyRingsUri() {
@ -121,6 +117,24 @@ public class KeychainContract {
return CONTENT_URI.buildUpon().appendPath(masterKeyId).build(); return CONTENT_URI.buildUpon().appendPath(masterKeyId).build();
} }
public static Uri buildUnifiedKeyRingUri(String masterKeyId) {
return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_UNIFIED).build();
}
public static Uri buildUnifiedKeyRingUri(Uri uri) {
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_UNIFIED).build();
}
}
public static class KeyRingData implements KeyRingsColumns, BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_KEY_RINGS).build();
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring_data";
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring_data";
public static Uri buildPublicKeyRingUri() {
return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).build();
}
public static Uri buildPublicKeyRingUri(String masterKeyId) { public static Uri buildPublicKeyRingUri(String masterKeyId) {
return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_PUBLIC).build(); return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_PUBLIC).build();
} }
@ -135,12 +149,6 @@ public class KeychainContract {
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_SECRET).build(); return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_SECRET).build();
} }
public static Uri buildUnifiedKeyRingUri(String masterKeyId) {
return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_UNIFIED).build();
}
public static Uri buildUnifiedKeyRingUri(Uri uri) {
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_UNIFIED).build();
}
} }
public static class Keys implements KeysColumns, BaseColumns { public static class Keys implements KeysColumns, BaseColumns {

View File

@ -26,19 +26,15 @@ import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder; import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri; import android.net.Uri;
import android.provider.BaseColumns;
import android.text.TextUtils; import android.text.TextUtils;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns;
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;
@ -46,13 +42,9 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
public class KeychainProvider extends ContentProvider { public class KeychainProvider extends ContentProvider {
// public static final String ACTION_BROADCAST_DATABASE_CHANGE = Constants.PACKAGE_NAME
// + ".action.DATABASE_CHANGE";
//
// public static final String EXTRA_BROADCAST_KEY_TYPE = "key_type";
// public static final String EXTRA_BROADCAST_CONTENT_ITEM_TYPE = "contentItemType";
private static final int KEY_RINGS_UNIFIED = 101; private static final int KEY_RINGS_UNIFIED = 101;
private static final int KEY_RINGS_PUBLIC = 102;
private static final int KEY_RING_UNIFIED = 200; private static final int KEY_RING_UNIFIED = 200;
private static final int KEY_RING_KEYS = 201; private static final int KEY_RING_KEYS = 201;
@ -79,18 +71,22 @@ public class KeychainProvider extends ContentProvider {
String authority = KeychainContract.CONTENT_AUTHORITY; String authority = KeychainContract.CONTENT_AUTHORITY;
/** /**
* select from key_ring * list key_rings
* *
* <pre> * <pre>
* key_rings/unified * key_rings/unified
* key_rings/public
* </pre> * </pre>
*/ */
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS
+ "/" + KeychainContract.PATH_UNIFIED, + "/" + KeychainContract.PATH_UNIFIED,
KEY_RINGS_UNIFIED); KEY_RINGS_UNIFIED);
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS
+ "/" + KeychainContract.PATH_PUBLIC,
KEY_RINGS_PUBLIC);
/** /**
* select from key_ring * list key_ring specifics
* *
* <pre> * <pre>
* key_rings/_/unified * key_rings/_/unified
@ -215,45 +211,44 @@ public class KeychainProvider extends ContentProvider {
case KEY_RING_UNIFIED: case KEY_RING_UNIFIED:
case KEY_RINGS_UNIFIED: { case KEY_RINGS_UNIFIED: {
HashMap<String, String> projectionMap = new HashMap<String, String>(); HashMap<String, String> projectionMap = new HashMap<String, String>();
projectionMap.put(BaseColumns._ID, Tables.KEYS + ".oid AS _id"); projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id");
projectionMap.put(KeysColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID); projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
projectionMap.put(KeysColumns.RANK, Tables.KEYS + "." + KeysColumns.RANK); projectionMap.put(KeyRings.KEY_ID, Keys.KEY_ID);
projectionMap.put(KeysColumns.KEY_ID, KeysColumns.KEY_ID); projectionMap.put(KeyRings.KEY_SIZE, Keys.KEY_SIZE);
projectionMap.put(KeysColumns.KEY_SIZE, KeysColumns.KEY_SIZE); projectionMap.put(KeyRings.IS_REVOKED, Keys.IS_REVOKED);
projectionMap.put(KeysColumns.IS_REVOKED, KeysColumns.IS_REVOKED); projectionMap.put(KeyRings.CAN_CERTIFY, Keys.CAN_CERTIFY);
projectionMap.put(KeysColumns.CAN_CERTIFY, KeysColumns.CAN_CERTIFY); projectionMap.put(KeyRings.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
projectionMap.put(KeysColumns.CAN_ENCRYPT, KeysColumns.CAN_ENCRYPT); projectionMap.put(KeyRings.CAN_SIGN, Keys.CAN_SIGN);
projectionMap.put(KeysColumns.CAN_SIGN, KeysColumns.CAN_SIGN); projectionMap.put(KeyRings.CREATION, Keys.CREATION);
projectionMap.put(KeysColumns.CREATION, KeysColumns.CREATION); projectionMap.put(KeyRings.EXPIRY, Keys.EXPIRY);
projectionMap.put(KeysColumns.EXPIRY, KeysColumns.EXPIRY); projectionMap.put(KeyRings.ALGORITHM, Keys.ALGORITHM);
projectionMap.put(KeysColumns.ALGORITHM, KeysColumns.ALGORITHM); projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT);
projectionMap.put(KeysColumns.FINGERPRINT, KeysColumns.FINGERPRINT); projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID);
projectionMap.put(UserIdsColumns.USER_ID, UserIdsColumns.USER_ID); projectionMap.put(KeyRings.HAS_SECRET, "(" + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NOT NULL) AS " + KeyRings.HAS_SECRET);
projectionMap.put(Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID, Tables.KEY_RINGS_SECRET + "." + KeyRingsColumns.MASTER_KEY_ID);
qb.setProjectionMap(projectionMap); qb.setProjectionMap(projectionMap);
qb.setTables( qb.setTables(
Tables.KEYS Tables.KEYS
+ " INNER JOIN " + Tables.USER_IDS + " ON (" + " INNER JOIN " + Tables.USER_IDS + " ON ("
+ Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ " = " + " = "
+ Tables.USER_IDS + "." + UserIdsColumns.MASTER_KEY_ID + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID
+ " AND " + Tables.USER_IDS + "." + UserIdsColumns.RANK + " = 0" + " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = 0"
+ ") LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON (" + ") LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON ("
+ Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ " = " + " = "
+ Tables.KEY_RINGS_SECRET + "." + KeyRingsColumns.MASTER_KEY_ID + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID
+ ")" + ")"
); );
qb.appendWhere(Tables.KEYS + "." + KeysColumns.RANK + " = 0"); qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0");
if(match == KEY_RING_UNIFIED) { if(match == KEY_RING_UNIFIED) {
qb.appendWhere(" AND " + Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID + " = "); qb.appendWhere(" AND " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1)); qb.appendWhereEscapeString(uri.getPathSegments().get(1));
} else if (TextUtils.isEmpty(sortOrder)) { } else if (TextUtils.isEmpty(sortOrder)) {
sortOrder = sortOrder =
Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL DESC" Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL DESC"
+ Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC"; + Tables.USER_IDS + "." + UserIds.USER_ID + " ASC";
} }
// uri to watch is all /key_rings/ // uri to watch is all /key_rings/
@ -276,38 +271,38 @@ public class KeychainProvider extends ContentProvider {
if (i != 0) { if (i != 0) {
emailWhere += " OR "; emailWhere += " OR ";
} }
emailWhere += "tmp." + UserIdsColumns.USER_ID + " LIKE "; emailWhere += "tmp." + UserIds.USER_ID + " LIKE ";
// match '*<email>', so it has to be at the *end* of the user id // match '*<email>', so it has to be at the *end* of the user id
emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">"); emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">");
gotCondition = true; gotCondition = true;
} }
if (gotCondition) { if (gotCondition) {
qb.appendWhere(" AND EXISTS (SELECT tmp." + BaseColumns._ID + " FROM " qb.appendWhere(" AND EXISTS (SELECT tmp." + Base._ID + " FROM "
+ Tables.USER_IDS + " AS tmp WHERE tmp." + UserIdsColumns.KEY_RING_ROW_ID + Tables.USER_IDS + " AS tmp WHERE tmp." + UserIds.KEY_RING_ROW_ID
+ " = " + Tables.KEY_RINGS + "." + BaseColumns._ID + " AND (" + emailWhere + " = " + Tables.KEY_RINGS + "." + Base._ID + " AND (" + emailWhere
+ "))"); + "))");
}*/ }*/
case KEY_RING_KEYS: { case KEY_RING_KEYS: {
HashMap<String, String> projectionMap = new HashMap<String, String>(); HashMap<String, String> projectionMap = new HashMap<String, String>();
projectionMap.put(BaseColumns._ID, Tables.KEYS + ".oid AS _id"); projectionMap.put(Keys._ID, Tables.KEYS + ".oid AS _id");
projectionMap.put(KeysColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID); projectionMap.put(Keys.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
projectionMap.put(KeysColumns.RANK, Tables.KEYS + "." + KeysColumns.RANK); projectionMap.put(Keys.RANK, Tables.KEYS + "." + Keys.RANK);
projectionMap.put(KeysColumns.KEY_ID, KeysColumns.KEY_ID); projectionMap.put(Keys.KEY_ID, Keys.KEY_ID);
projectionMap.put(KeysColumns.KEY_SIZE, KeysColumns.KEY_SIZE); projectionMap.put(Keys.KEY_SIZE, Keys.KEY_SIZE);
projectionMap.put(KeysColumns.IS_REVOKED, KeysColumns.IS_REVOKED); projectionMap.put(Keys.IS_REVOKED, Keys.IS_REVOKED);
projectionMap.put(KeysColumns.CAN_CERTIFY, KeysColumns.CAN_CERTIFY); projectionMap.put(Keys.CAN_CERTIFY, Keys.CAN_CERTIFY);
projectionMap.put(KeysColumns.CAN_ENCRYPT, KeysColumns.CAN_ENCRYPT); projectionMap.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
projectionMap.put(KeysColumns.CAN_SIGN, KeysColumns.CAN_SIGN); projectionMap.put(Keys.CAN_SIGN, Keys.CAN_SIGN);
projectionMap.put(KeysColumns.CREATION, KeysColumns.CREATION); projectionMap.put(Keys.CREATION, Keys.CREATION);
projectionMap.put(KeysColumns.EXPIRY, KeysColumns.EXPIRY); projectionMap.put(Keys.EXPIRY, Keys.EXPIRY);
projectionMap.put(KeysColumns.ALGORITHM, KeysColumns.ALGORITHM); projectionMap.put(Keys.ALGORITHM, Keys.ALGORITHM);
projectionMap.put(KeysColumns.FINGERPRINT, KeysColumns.FINGERPRINT); projectionMap.put(Keys.FINGERPRINT, Keys.FINGERPRINT);
qb.setProjectionMap(projectionMap); qb.setProjectionMap(projectionMap);
qb.setTables(Tables.KEYS); qb.setTables(Tables.KEYS);
qb.appendWhere(KeysColumns.MASTER_KEY_ID + " = "); qb.appendWhere(Keys.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1)); qb.appendWhereEscapeString(uri.getPathSegments().get(1));
break; break;
@ -315,7 +310,7 @@ public class KeychainProvider extends ContentProvider {
case KEY_RING_USER_IDS: { case KEY_RING_USER_IDS: {
HashMap<String, String> projectionMap = new HashMap<String, String>(); HashMap<String, String> projectionMap = new HashMap<String, String>();
projectionMap.put(BaseColumns._ID, Tables.USER_IDS + ".oid AS _id"); projectionMap.put(UserIds._ID, Tables.USER_IDS + ".oid AS _id");
projectionMap.put(UserIds.MASTER_KEY_ID, UserIds.MASTER_KEY_ID); projectionMap.put(UserIds.MASTER_KEY_ID, UserIds.MASTER_KEY_ID);
projectionMap.put(UserIds.USER_ID, UserIds.USER_ID); projectionMap.put(UserIds.USER_ID, UserIds.USER_ID);
projectionMap.put(UserIds.RANK, UserIds.RANK); projectionMap.put(UserIds.RANK, UserIds.RANK);
@ -323,36 +318,44 @@ public class KeychainProvider extends ContentProvider {
qb.setProjectionMap(projectionMap); qb.setProjectionMap(projectionMap);
qb.setTables(Tables.USER_IDS); qb.setTables(Tables.USER_IDS);
qb.appendWhere(UserIdsColumns.MASTER_KEY_ID + " = "); qb.appendWhere(UserIds.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1)); qb.appendWhereEscapeString(uri.getPathSegments().get(1));
if (TextUtils.isEmpty(sortOrder)) {
sortOrder = UserIds.RANK + " ASC";
}
break; break;
} }
case KEY_RINGS_PUBLIC:
case KEY_RING_PUBLIC: { case KEY_RING_PUBLIC: {
HashMap<String, String> projectionMap = new HashMap<String, String>(); HashMap<String, String> projectionMap = new HashMap<String, String>();
projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS_PUBLIC + ".oid AS _id"); projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_PUBLIC + ".oid AS _id");
projectionMap.put(KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID); projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID);
projectionMap.put(KeyRings.KEY_RING_DATA, KeyRings.KEY_RING_DATA); projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA);
qb.setProjectionMap(projectionMap); qb.setProjectionMap(projectionMap);
qb.setTables(Tables.KEY_RINGS_PUBLIC); qb.setTables(Tables.KEY_RINGS_PUBLIC);
qb.appendWhere(KeyRingsColumns.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1)); if(match == KEY_RING_PUBLIC) {
qb.appendWhere(KeyRings.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
}
break; break;
} }
case KEY_RING_SECRET: { case KEY_RING_SECRET: {
HashMap<String, String> projectionMap = new HashMap<String, String>(); HashMap<String, String> projectionMap = new HashMap<String, String>();
projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS_SECRET + ".oid AS _id"); projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_SECRET + ".oid AS _id");
projectionMap.put(KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID); projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID);
projectionMap.put(KeyRings.KEY_RING_DATA, KeyRings.KEY_RING_DATA); projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA);
qb.setProjectionMap(projectionMap); qb.setProjectionMap(projectionMap);
qb.setTables(Tables.KEY_RINGS_SECRET); qb.setTables(Tables.KEY_RINGS_SECRET);
qb.appendWhere(KeyRingsColumns.MASTER_KEY_ID + " = "); qb.appendWhere(KeyRings.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1)); qb.appendWhereEscapeString(uri.getPathSegments().get(1));
break; break;
@ -429,23 +432,23 @@ public class KeychainProvider extends ContentProvider {
switch (match) { switch (match) {
case KEY_RING_PUBLIC: case KEY_RING_PUBLIC:
db.insertOrThrow(Tables.KEY_RINGS_PUBLIC, null, values); db.insertOrThrow(Tables.KEY_RINGS_PUBLIC, null, values);
keyId = values.getAsLong(KeyRingsColumns.MASTER_KEY_ID); keyId = values.getAsLong(KeyRings.MASTER_KEY_ID);
break; break;
case KEY_RING_SECRET: case KEY_RING_SECRET:
db.insertOrThrow(Tables.KEY_RINGS_SECRET, null, values); db.insertOrThrow(Tables.KEY_RINGS_SECRET, null, values);
keyId = values.getAsLong(KeyRingsColumns.MASTER_KEY_ID); keyId = values.getAsLong(KeyRings.MASTER_KEY_ID);
break; break;
case KEY_RING_KEYS: case KEY_RING_KEYS:
Log.d(Constants.TAG, "keys"); Log.d(Constants.TAG, "keys");
db.insertOrThrow(Tables.KEYS, null, values); db.insertOrThrow(Tables.KEYS, null, values);
keyId = values.getAsLong(KeysColumns.MASTER_KEY_ID); keyId = values.getAsLong(Keys.MASTER_KEY_ID);
break; break;
case KEY_RING_USER_IDS: case KEY_RING_USER_IDS:
db.insertOrThrow(Tables.USER_IDS, null, values); db.insertOrThrow(Tables.USER_IDS, null, values);
keyId = values.getAsLong(UserIdsColumns.MASTER_KEY_ID); keyId = values.getAsLong(UserIds.MASTER_KEY_ID);
break; break;
case API_APPS: case API_APPS:

View File

@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.remote.AccountSettings;
@ -65,11 +66,11 @@ public class ProviderHelper {
*/ */
public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) { public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) {
Cursor cursor = context.getContentResolver().query(queryUri, Cursor cursor = context.getContentResolver().query(queryUri,
new String[]{KeyRings._ID, KeyRings.KEY_RING_DATA}, null, null, null); new String[]{KeyRings._ID, KeyRingData.KEY_RING_DATA}, null, null, null);
PGPKeyRing keyRing = null; PGPKeyRing keyRing = null;
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
int keyRingDataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA); int keyRingDataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
byte[] data = cursor.getBlob(keyRingDataCol); byte[] data = cursor.getBlob(keyRingDataCol);
if (data != null) { if (data != null) {
@ -156,7 +157,7 @@ public class ProviderHelper {
*/ */
public static PGPPublicKeyRing getPGPPublicKeyRing(Context context, public static PGPPublicKeyRing getPGPPublicKeyRing(Context context,
long masterKeyId) { long masterKeyId) {
Uri queryUri = KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)); Uri queryUri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId));
return (PGPPublicKeyRing) getPGPKeyRing(context, queryUri); return (PGPPublicKeyRing) getPGPKeyRing(context, queryUri);
} }
@ -165,7 +166,7 @@ public class ProviderHelper {
*/ */
public static PGPSecretKeyRing getPGPSecretKeyRing(Context context, public static PGPSecretKeyRing getPGPSecretKeyRing(Context context,
long masterKeyId) { long masterKeyId) {
Uri queryUri = KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId)); Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
return (PGPSecretKeyRing) getPGPKeyRing(context, queryUri); return (PGPSecretKeyRing) getPGPKeyRing(context, queryUri);
} }
@ -178,12 +179,11 @@ public class ProviderHelper {
long masterKeyId = masterKey.getKeyID(); long masterKeyId = masterKey.getKeyID();
// IF there is a secret key, preserve it! // IF there is a secret key, preserve it!
// TODO This even necessary? PGPSecretKeyRing secretRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId);
// PGPSecretKeyRing secretRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId);
// delete old version of this keyRing, which also deletes all keys and userIds on cascade // delete old version of this keyRing, which also deletes all keys and userIds on cascade
try { try {
context.getContentResolver().delete(KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null); context.getContentResolver().delete(KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null);
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
Log.e(Constants.TAG, "Key could not be deleted! Maybe we are creating a new one!", e); Log.e(Constants.TAG, "Key could not be deleted! Maybe we are creating a new one!", e);
} }
@ -193,11 +193,11 @@ public class ProviderHelper {
// NOTE: If we would not use the same _ID again, // NOTE: If we would not use the same _ID again,
// getting back to the ViewKeyActivity would result in Nullpointer, // getting back to the ViewKeyActivity would result in Nullpointer,
// because the currently loaded key would be gone from the database // because the currently loaded key would be gone from the database
values.put(KeyRings.MASTER_KEY_ID, masterKeyId); values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded()); values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded());
// insert new version of this keyRing // insert new version of this keyRing
Uri uri = KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)); Uri uri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId));
Uri insertedUri = context.getContentResolver().insert(uri, values); Uri insertedUri = context.getContentResolver().insert(uri, values);
// save all keys and userIds included in keyRing object in database // save all keys and userIds included in keyRing object in database
@ -233,31 +233,43 @@ public class ProviderHelper {
} }
// Save the saved keyring (if any) // Save the saved keyring (if any)
// TODO this even necessary? see above... if(secretRing != null) {
// if(secretRing != null) saveKeyRing(context, secretRing);
// saveKeyRing(context, secretRing); }
} }
/** /**
* Saves PGPSecretKeyRing with its keys and userIds in DB * Saves a PGPSecretKeyRing in the DB. This will only work if a corresponding public keyring
* is already in the database!
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static void saveKeyRing(Context context, PGPSecretKeyRing keyRing) throws IOException { public static void saveKeyRing(Context context, PGPSecretKeyRing keyRing) throws IOException {
PGPSecretKey masterKey = keyRing.getSecretKey(); long masterKeyId = keyRing.getPublicKey().getKeyID();
long masterKeyId = masterKey.getKeyID();
// TODO Make sure there is a public key for this secret key in the db (create one maybe) // save secret keyring
ContentValues values = new ContentValues();
values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded());
// insert new version of this keyRing
Uri uri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
context.getContentResolver().insert(uri, values);
{ }
ContentValues values = new ContentValues();
values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
// insert new version of this keyRing
Uri uri = KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId));
context.getContentResolver().insert(uri, values);
}
/**
* Saves (or updates) a pair of public and secret KeyRings in the database
*/
@SuppressWarnings("unchecked")
public static void saveKeyRing(Context context, PGPPublicKeyRing pubRing, PGPSecretKeyRing privRing) throws IOException {
long masterKeyId = pubRing.getPublicKey().getKeyID();
// delete secret keyring (so it isn't unnecessarily saved by public-saveKeyRing below)
context.getContentResolver().delete(KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null);
// save public keyring
saveKeyRing(context, pubRing);
saveKeyRing(context, privRing);
} }
/** /**
@ -314,24 +326,14 @@ public class ProviderHelper {
return ContentProviderOperation.newInsert(uri).withValues(values).build(); return ContentProviderOperation.newInsert(uri).withValues(values).build();
} }
public static void deletePublicKeyRing(Context context, long masterKeyId) {
ContentResolver cr = context.getContentResolver();
cr.delete(KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null);
}
public static void deleteSecretKeyRing(Context context, long masterKeyId) {
ContentResolver cr = context.getContentResolver();
cr.delete(KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null);
}
public static boolean hasSecretKeyByMasterKeyId(Context context, long masterKeyId) { public static boolean hasSecretKeyByMasterKeyId(Context context, long masterKeyId) {
Uri queryUri = KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId)); Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
// see if we can get our master key id back from the uri // see if we can get our master key id back from the uri
return getMasterKeyId(context, queryUri) == masterKeyId; return getMasterKeyId(context, queryUri) == masterKeyId;
} }
/** /** Find the master key id related to a given query. The id will either be extracted from the
* Get master key id of key * query, which should work for all specific /key_rings/ queries, or will be queried if it can't.
*/ */
public static long getMasterKeyId(Context context, Uri queryUri) { public static long getMasterKeyId(Context context, Uri queryUri) {
// try extracting from the uri first // try extracting from the uri first
@ -339,39 +341,25 @@ public class ProviderHelper {
return Long.parseLong(queryUri.getPathSegments().get(1)); return Long.parseLong(queryUri.getPathSegments().get(1));
} catch(NumberFormatException e) { } catch(NumberFormatException e) {
// didn't work? oh well. // didn't work? oh well.
Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying...");
} }
Object data = getUnifiedData(context, queryUri, KeyRings.MASTER_KEY_ID);
Cursor cursor = context.getContentResolver().query(queryUri, new String[] { if(data instanceof Long)
KeyRings.MASTER_KEY_ID return (Long) data;
}, null, null, null); // TODO better error handling?
return 0L;
long masterKeyId = 0;
try {
if (cursor != null && cursor.moveToFirst()) {
int masterKeyIdCol = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID);
masterKeyId = cursor.getLong(masterKeyIdCol);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
return masterKeyId;
} }
public static ArrayList<String> getKeyRingsAsArmoredString(Context context, Uri uri, public static ArrayList<String> getKeyRingsAsArmoredString(Context context, long[] masterKeyIds) {
long[] masterKeyIds) {
ArrayList<String> output = new ArrayList<String>(); ArrayList<String> output = new ArrayList<String>();
if (masterKeyIds != null && masterKeyIds.length > 0) { if (masterKeyIds != null && masterKeyIds.length > 0) {
Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, uri, masterKeyIds); Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, masterKeyIds);
if (cursor != null) { if (cursor != null) {
int masterIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID); int masterIdCol = cursor.getColumnIndex(KeyRingData.MASTER_KEY_ID);
int dataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA); int dataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do {
Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol)); Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol));
@ -421,48 +409,11 @@ public class ProviderHelper {
return null; return null;
} }
} }
private static Cursor getCursorWithSelectedKeyringMasterKeyIds(Context context, long[] masterKeyIds) {
public static byte[] getKeyRingsAsByteArray(Context context, Uri uri, long[] masterKeyIds) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
if (masterKeyIds != null && masterKeyIds.length > 0) {
Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, uri, masterKeyIds);
if (cursor != null) {
int masterIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
int dataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA);
if (cursor.moveToFirst()) {
do {
Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol));
// get actual keyring data blob and write it to ByteArrayOutputStream
try {
bos.write(cursor.getBlob(dataCol));
} catch (IOException e) {
Log.e(Constants.TAG, "IOException", e);
}
} while (cursor.moveToNext());
}
}
if (cursor != null) {
cursor.close();
}
} else {
Log.e(Constants.TAG, "No master keys given!");
}
return bos.toByteArray();
}
private static Cursor getCursorWithSelectedKeyringMasterKeyIds(Context context, Uri baseUri,
long[] masterKeyIds) {
Cursor cursor = null; Cursor cursor = null;
if (masterKeyIds != null && masterKeyIds.length > 0) { if (masterKeyIds != null && masterKeyIds.length > 0) {
String inMasterKeyList = KeyRings.MASTER_KEY_ID + " IN ("; String inMasterKeyList = KeyRingData.MASTER_KEY_ID + " IN (";
for (int i = 0; i < masterKeyIds.length; ++i) { for (int i = 0; i < masterKeyIds.length; ++i) {
if (i != 0) { if (i != 0) {
inMasterKeyList += ", "; inMasterKeyList += ", ";
@ -471,9 +422,9 @@ public class ProviderHelper {
} }
inMasterKeyList += ")"; inMasterKeyList += ")";
cursor = context.getContentResolver().query(baseUri, cursor = context.getContentResolver().query(KeyRingData.buildPublicKeyRingUri(), new String[] {
new String[]{KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.KEY_RING_DATA}, KeyRingData._ID, KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA
inMasterKeyList, null, null); }, inMasterKeyList, null, null);
} }
return cursor; return cursor;

View File

@ -518,8 +518,8 @@ public class KeychainIntentService extends IntentService
PgpKeyOperation.Pair<PGPSecretKeyRing,PGPPublicKeyRing> pair = PgpKeyOperation.Pair<PGPSecretKeyRing,PGPPublicKeyRing> pair =
keyOperations.buildSecretKey(privkey, pubkey, saveParams); keyOperations.buildSecretKey(privkey, pubkey, saveParams);
setProgress(R.string.progress_saving_key_ring, 90, 100); setProgress(R.string.progress_saving_key_ring, 90, 100);
ProviderHelper.saveKeyRing(this, pair.first); // save the pair
ProviderHelper.saveKeyRing(this, pair.second); ProviderHelper.saveKeyRing(this, pair.second, pair.first);
setProgress(R.string.progress_done, 100, 100); setProgress(R.string.progress_done, 100, 100);
} }
PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase); PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase);

View File

@ -57,6 +57,7 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.PassphraseCacheService;
@ -345,7 +346,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
} }
return true; return true;
case R.id.menu_key_edit_delete: case R.id.menu_key_edit_delete:
Uri convertUri = KeychainContract.KeyRings.buildSecretKeyRingUri(mDataUri); Uri convertUri = KeyRingData.buildSecretKeyRingUri(mDataUri);
// Message is received after key is deleted // Message is received after key is deleted
Handler returnHandler = new Handler() { Handler returnHandler = new Handler() {
@Override @Override

View File

@ -58,12 +58,9 @@ import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ExportHelper; import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter; import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
@ -257,11 +254,11 @@ public class KeyListFragment extends Fragment
// These are the rows that we will retrieve. // These are the rows that we will retrieve.
static final String[] PROJECTION = new String[]{ static final String[] PROJECTION = new String[]{
KeychainContract.KeyRings._ID, KeyRings._ID,
KeychainContract.Keys.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID,
KeychainContract.UserIds.USER_ID, KeyRings.USER_ID,
KeychainContract.Keys.IS_REVOKED, KeyRings.IS_REVOKED,
KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID KeyRings.HAS_SECRET
}; };
static final int INDEX_MASTER_KEY_ID = 1; static final int INDEX_MASTER_KEY_ID = 1;
@ -269,11 +266,8 @@ public class KeyListFragment extends Fragment
static final int INDEX_IS_REVOKED = 3; static final int INDEX_IS_REVOKED = 3;
static final int INDEX_HAS_SECRET = 4; static final int INDEX_HAS_SECRET = 4;
static final String SORT_ORDER = // show secret before public key, sort by user id otherwise
// show secret before public key static final String SORT_ORDER = KeyRings.HAS_SECRET + " DESC, " + UserIds.USER_ID + " ASC";
KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID + " IS NULL ASC, " +
// sort by user id otherwise
UserIds.USER_ID + " ASC";
@Override @Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) { public Loader<Cursor> onCreateLoader(int id, Bundle args) {
@ -283,7 +277,7 @@ public class KeyListFragment extends Fragment
String where = null; String where = null;
String whereArgs[] = null; String whereArgs[] = null;
if (mCurQuery != null) { if (mCurQuery != null) {
where = KeychainContract.UserIds.USER_ID + " LIKE ?"; where = KeyRings.USER_ID + " LIKE ?";
whereArgs = new String[]{"%" + mCurQuery + "%"}; whereArgs = new String[]{"%" + mCurQuery + "%"};
} }
// Now create and return a CursorLoader that will take care of // Now create and return a CursorLoader that will take care of
@ -329,17 +323,15 @@ public class KeyListFragment extends Fragment
viewIntent = new Intent(getActivity(), ViewKeyActivityJB.class); viewIntent = new Intent(getActivity(), ViewKeyActivityJB.class);
} }
viewIntent.setData( viewIntent.setData(
KeychainContract KeyRings.buildGenericKeyRingUri(Long.toString(mAdapter.getMasterKeyId(position))));
.KeyRings.buildGenericKeyRingUri(
Long.toString(mAdapter.getMasterKeyId(position))));
startActivity(viewIntent); startActivity(viewIntent);
} }
@TargetApi(11) @TargetApi(11)
protected void encrypt(ActionMode mode, long[] keyRingMasterKeyIds) { protected void encrypt(ActionMode mode, long[] masterKeyIds) {
Intent intent = new Intent(getActivity(), EncryptActivity.class); Intent intent = new Intent(getActivity(), EncryptActivity.class);
intent.setAction(EncryptActivity.ACTION_ENCRYPT); intent.setAction(EncryptActivity.ACTION_ENCRYPT);
intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, keyRingMasterKeyIds); intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, masterKeyIds);
// used instead of startActivity set actionbar based on callingPackage // used instead of startActivity set actionbar based on callingPackage
startActivityForResult(intent, 0); startActivityForResult(intent, 0);
@ -507,7 +499,7 @@ public class KeyListFragment extends Fragment
Button button = (Button) view.findViewById(R.id.edit); Button button = (Button) view.findViewById(R.id.edit);
TextView revoked = (TextView) view.findViewById(R.id.revoked); TextView revoked = (TextView) view.findViewById(R.id.revoked);
if (!cursor.isNull(KeyListFragment.INDEX_HAS_SECRET)) { if (cursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
// this is a secret key - show the edit button // this is a secret key - show the edit button
statusDivider.setVisibility(View.VISIBLE); statusDivider.setVisibility(View.VISIBLE);
statusLayout.setVisibility(View.VISIBLE); statusLayout.setVisibility(View.VISIBLE);
@ -518,9 +510,7 @@ public class KeyListFragment extends Fragment
button.setOnClickListener(new OnClickListener() { button.setOnClickListener(new OnClickListener() {
public void onClick(View view) { public void onClick(View view) {
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
editIntent.setData( editIntent.setData(KeyRingData.buildSecretKeyRingUri(Long.toString(id)));
KeychainContract.KeyRings
.buildSecretKeyRingUri(Long.toString(id)));
editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY); editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
startActivityForResult(editIntent, 0); startActivityForResult(editIntent, 0);
} }
@ -581,7 +571,7 @@ public class KeyListFragment extends Fragment
throw new IllegalStateException("couldn't move cursor to position " + position); throw new IllegalStateException("couldn't move cursor to position " + position);
} }
if (!mCursor.isNull(KeyListFragment.INDEX_HAS_SECRET)) { if (mCursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
{ // set contact count { // set contact count
int num = mCursor.getCount(); int num = mCursor.getCount();
String contactsTotal = getResources().getQuantityString(R.plurals.n_contacts, num, num); String contactsTotal = getResources().getQuantityString(R.plurals.n_contacts, num, num);
@ -621,7 +611,7 @@ public class KeyListFragment extends Fragment
} }
// early breakout: all secret keys are assigned id 0 // early breakout: all secret keys are assigned id 0
if (!mCursor.isNull(KeyListFragment.INDEX_HAS_SECRET)) { if (mCursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
return 1L; return 1L;
} }
// otherwise, return the first character of the name as ID // otherwise, return the first character of the name as ID

View File

@ -185,8 +185,8 @@ public class ViewKeyActivity extends ActionBarActivity {
} else { } else {
// get public keyring as ascii armored string // get public keyring as ascii armored string
long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
dataUri, new long[]{masterKeyId}); this, new long[]{ masterKeyId });
content = keyringArmored.get(0); content = keyringArmored.get(0);
@ -216,8 +216,8 @@ public class ViewKeyActivity extends ActionBarActivity {
private void copyToClipboard(Uri dataUri) { private void copyToClipboard(Uri dataUri) {
// get public keyring as ascii armored string // get public keyring as ascii armored string
long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri, ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
new long[]{masterKeyId}); this, new long[]{ masterKeyId });
ClipboardReflection.copyToClipboard(this, keyringArmored.get(0)); ClipboardReflection.copyToClipboard(this, keyringArmored.get(0));
Toast.makeText(getApplicationContext(), R.string.key_copied_to_clipboard, Toast.LENGTH_LONG) Toast.makeText(getApplicationContext(), R.string.key_copied_to_clipboard, Toast.LENGTH_LONG)

View File

@ -38,7 +38,10 @@ import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter;
import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter; import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter;
@ -124,6 +127,7 @@ public class ViewKeyMainFragment extends Fragment implements
{ // label whether secret key is available, and edit button if it is { // label whether secret key is available, and edit button if it is
final long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), mDataUri); final long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), mDataUri);
// TODO do this some other way...
if (ProviderHelper.hasSecretKeyByMasterKeyId(getActivity(), masterKeyId)) { if (ProviderHelper.hasSecretKeyByMasterKeyId(getActivity(), masterKeyId)) {
// set this attribute. this is a LITTLE unclean, but we have the info available // set this attribute. this is a LITTLE unclean, but we have the info available
// right here, so why not. // right here, so why not.
@ -141,8 +145,7 @@ public class ViewKeyMainFragment extends Fragment implements
public void onClick(View view) { public void onClick(View view) {
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
editIntent.setData( editIntent.setData(
KeychainContract KeyRingData.buildSecretKeyRingUri(
.KeyRings.buildSecretKeyRingUri(
Long.toString(masterKeyId))); Long.toString(masterKeyId)));
editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY); editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
startActivityForResult(editIntent, 0); startActivityForResult(editIntent, 0);
@ -161,7 +164,7 @@ public class ViewKeyMainFragment extends Fragment implements
// TODO see todo note above, doing this here for now // TODO see todo note above, doing this here for now
mActionCertify.setOnClickListener(new View.OnClickListener() { mActionCertify.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) { public void onClick(View view) {
certifyKey(KeychainContract.KeyRings.buildGenericKeyRingUri( certifyKey(KeyRings.buildGenericKeyRingUri(
Long.toString(masterKeyId) Long.toString(masterKeyId)
)); ));
} }
@ -190,31 +193,26 @@ public class ViewKeyMainFragment extends Fragment implements
} }
static final String[] USER_IDS_PROJECTION = static final String[] USER_IDS_PROJECTION =
new String[]{ new String[] {
KeychainContract.UserIds._ID, UserIds._ID,
KeychainContract.UserIds.USER_ID, UserIds.USER_ID,
KeychainContract.UserIds.RANK, UserIds.RANK,
}; };
static final int INDEX_UID_UID = 1; static final int INDEX_UID_UID = 1;
static final String USER_IDS_SORT_ORDER =
KeychainContract.UserIds.RANK + " COLLATE LOCALIZED ASC";
static final String[] KEYS_PROJECTION = static final String[] KEYS_PROJECTION = new String[] {
new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID, Keys._ID,
KeychainContract.Keys.ALGORITHM, KeychainContract.Keys.RANK, Keys.KEY_ID, Keys.RANK,
KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY, Keys.ALGORITHM, Keys.KEY_SIZE,
KeychainContract.Keys.CAN_SIGN, KeychainContract.Keys.CAN_ENCRYPT, Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT,
KeychainContract.Keys.IS_REVOKED, KeychainContract.Keys.CREATION, Keys.CAN_SIGN, Keys.IS_REVOKED,
KeychainContract.Keys.EXPIRY, KeychainContract.Keys.FINGERPRINT}; Keys.CREATION, Keys.EXPIRY,
static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC"; Keys.FINGERPRINT
};
static final int KEYS_INDEX_KEY_ID = 1; static final int KEYS_INDEX_KEY_ID = 1;
static final int KEYS_INDEX_ALGORITHM = 2; static final int KEYS_INDEX_ALGORITHM = 3;
static final int KEYS_INDEX_RANK = 3;
static final int KEYS_INDEX_KEY_SIZE = 4; static final int KEYS_INDEX_KEY_SIZE = 4;
static final int KEYS_INDEX_CAN_CERTIFY = 5; static final int KEYS_INDEX_CAN_ENCRYPT = 6;
static final int KEYS_INDEX_CAN_SIGN = 6;
static final int KEYS_INDEX_CAN_ENCRYPT = 7;
static final int KEYS_INDEX_IS_REVOKED = 8;
static final int KEYS_INDEX_CREATION = 9; static final int KEYS_INDEX_CREATION = 9;
static final int KEYS_INDEX_EXPIRY = 10; static final int KEYS_INDEX_EXPIRY = 10;
static final int KEYS_INDEX_FINGERPRINT = 11; static final int KEYS_INDEX_FINGERPRINT = 11;
@ -222,19 +220,18 @@ public class ViewKeyMainFragment extends Fragment implements
public Loader<Cursor> onCreateLoader(int id, Bundle args) { public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) { switch (id) {
case LOADER_ID_USER_IDS: { case LOADER_ID_USER_IDS: {
Uri baseUri = KeychainContract.UserIds.buildUserIdsUri(mDataUri); Uri baseUri = UserIds.buildUserIdsUri(mDataUri);
// Now create and return a CursorLoader that will take care of // Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed. // creating a Cursor for the data being displayed.
return new CursorLoader(getActivity(), baseUri, USER_IDS_PROJECTION, null, null, return new CursorLoader(getActivity(), baseUri, USER_IDS_PROJECTION, null, null, null);
USER_IDS_SORT_ORDER);
} }
case LOADER_ID_KEYS: { case LOADER_ID_KEYS: {
Uri baseUri = KeychainContract.Keys.buildKeysUri(mDataUri); Uri baseUri = Keys.buildKeysUri(mDataUri);
// Now create and return a CursorLoader that will take care of // Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed. // creating a Cursor for the data being displayed.
return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, KEYS_SORT_ORDER); return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, null);
} }
default: default:
@ -343,7 +340,7 @@ public class ViewKeyMainFragment extends Fragment implements
private void encryptToContact(Uri dataUri) { private void encryptToContact(Uri dataUri) {
// TODO preselect from uri? should be feasible without trivial query // TODO preselect from uri? should be feasible without trivial query
long keyId = Long.parseLong(dataUri.getPathSegments().get(1)); long keyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri);
long[] encryptionKeyIds = new long[]{ keyId }; long[] encryptionKeyIds = new long[]{ keyId };
Intent intent = new Intent(getActivity(), EncryptActivity.class); Intent intent = new Intent(getActivity(), EncryptActivity.class);

View File

@ -20,8 +20,6 @@ package org.sufficientlysecure.keychain.ui.dialog;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
@ -35,14 +33,13 @@ import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
public class DeleteKeyDialogFragment extends DialogFragment { public class DeleteKeyDialogFragment extends DialogFragment {
@ -107,13 +104,11 @@ public class DeleteKeyDialogFragment extends DialogFragment {
long masterKeyId = masterKeyIds[0]; long masterKeyId = masterKeyIds[0];
HashMap<String, Object> data = ProviderHelper.getUnifiedData(activity, masterKeyId, new String[]{ HashMap<String, Object> data = ProviderHelper.getUnifiedData(activity, masterKeyId, new String[]{
KeychainContract.UserIds.USER_ID, KeyRings.USER_ID,
KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID KeyRings.HAS_SECRET
}); });
String userId = (String) data.get(KeychainContract.UserIds.USER_ID); String userId = (String) data.get(KeyRings.USER_ID);
boolean hasSecret = data.get( boolean hasSecret = ((Long) data.get(KeyRings.HAS_SECRET)) == 1;
KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID
) instanceof Long;
// Hide the Checkbox and TextView since this is a single selection,user will be notified through message // Hide the Checkbox and TextView since this is a single selection,user will be notified through message
mDeleteSecretKeyView.setVisibility(View.GONE); mDeleteSecretKeyView.setVisibility(View.GONE);
@ -136,7 +131,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {
boolean success = false; boolean success = false;
for(long masterKeyId : masterKeyIds) { for(long masterKeyId : masterKeyIds) {
int count = activity.getContentResolver().delete( int count = activity.getContentResolver().delete(
KeychainContract.KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null
); );
if(count > 0) if(count > 0)
success = true; success = true;

View File

@ -107,7 +107,7 @@ public class ShareQrCodeDialogFragment extends DialogFragment {
long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri); long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri);
// get public keyring as ascii armored string // get public keyring as ascii armored string
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString( ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
getActivity(), dataUri, new long[] { masterKeyId }); getActivity(), new long[] { masterKeyId });
// TODO: binary? // TODO: binary?