diff options
Diffstat (limited to 'org_apg/src/org/thialfihar/android/apg/provider')
4 files changed, 610 insertions, 239 deletions
diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ApgContract.java b/org_apg/src/org/thialfihar/android/apg/provider/ApgContract.java index 66c611d4b..05a26157a 100644 --- a/org_apg/src/org/thialfihar/android/apg/provider/ApgContract.java +++ b/org_apg/src/org/thialfihar/android/apg/provider/ApgContract.java @@ -22,25 +22,12 @@ import org.thialfihar.android.apg.Constants; import android.net.Uri; import android.provider.BaseColumns; -/** - * TODO: - * - * Breaking compatibility?: - * - * - change CONTENT_AUTHORITY - * - * - change type names - * - */ public class ApgContract { - // APG1: all rows had a "c_" prefix - interface KeyRingsColumns { - String MASTER_KEY_ROW_ID = "master_key_id"; // TODO: clarify + String MASTER_KEY_ID = "master_key_id"; // not a database id String TYPE = "type"; // see KeyTypes - String WHO_ID = "who_id"; // TODO: is this used? - String KEY_RING_DATA = "key_ring_data"; // blob + String KEY_RING_DATA = "key_ring_data"; // PGPPublicKeyRing / PGPSecretKeyRing blob } interface KeysColumns { @@ -54,13 +41,13 @@ public class ApgContract { String IS_REVOKED = "is_revoked"; String CREATION = "creation"; String EXPIRY = "expiry"; - String KEY_RING_ROW_ID = "key_ring_id"; // foreign key to key_rings._ID - String KEY_DATA = "key_data"; // blob - String RANK = "rank"; // APG1: this was "key_data", TODO: Bug? Is this even used? + String KEY_RING_ROW_ID = "key_ring_row_id"; // foreign key to key_rings._ID + String KEY_DATA = "key_data"; // PGPPublicKey / PGPSecretKey blob + String RANK = "rank"; } interface UserIdsColumns { - String KEY_ROW_ID = "key_id"; // foreign key to keys._ID + String KEY_RING_ROW_ID = "key_ring_row_id"; // foreign key to key_rings._ID String USER_ID = "user_id"; // not a database id String RANK = "rank"; } @@ -70,7 +57,6 @@ public class ApgContract { public static final int SECRET = 1; } - // APG1: "org.thialfihar.android.apg.provider"; public static final String CONTENT_AUTHORITY = Constants.PACKAGE_NAME; private static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY); @@ -81,11 +67,10 @@ public class ApgContract { public static final String PATH_PUBLIC = "public"; public static final String PATH_SECRET = "secret"; + public static final String PATH_BY_MASTER_KEY_ID = "master_key_id"; public static final String PATH_BY_KEY_ID = "key_id"; public static final String PATH_BY_EMAILS = "emails"; - public static final String PATH_RANK = "#"; - public static final String PATH_USER_IDS = "user_ids"; public static final String PATH_KEYS = "keys"; @@ -107,8 +92,13 @@ public class ApgContract { return CONTENT_URI.buildUpon().appendPath(keyRingRowId).build(); } - public static Uri buildPublicKeyRingsByKeyIdUri(String keyRowId) { - return CONTENT_URI.buildUpon().appendPath(PATH_BY_KEY_ID).appendPath(keyRowId).build(); + public static Uri buildPublicKeyRingsByMasterKeyIdUri(String masterKeyId) { + return CONTENT_URI.buildUpon().appendPath(PATH_BY_MASTER_KEY_ID) + .appendPath(masterKeyId).build(); + } + + public static Uri buildPublicKeyRingsByKeyIdUri(String keyId) { + return CONTENT_URI.buildUpon().appendPath(PATH_BY_KEY_ID).appendPath(keyId).build(); } public static Uri buildPublicKeyRingsByEmailsUri(String emails) { @@ -134,8 +124,13 @@ public class ApgContract { return CONTENT_URI.buildUpon().appendPath(keyRingRowId).build(); } - public static Uri buildSecretKeyRingsByKeyIdUri(String keyRowId) { - return CONTENT_URI.buildUpon().appendPath(PATH_BY_KEY_ID).appendPath(keyRowId).build(); + public static Uri buildSecretKeyRingsByMasterKeyIdUri(String masterKeyId) { + return CONTENT_URI.buildUpon().appendPath(PATH_BY_MASTER_KEY_ID) + .appendPath(masterKeyId).build(); + } + + public static Uri buildSecretKeyRingsByKeyIdUri(String keyId) { + return CONTENT_URI.buildUpon().appendPath(PATH_BY_KEY_ID).appendPath(keyId).build(); } public static Uri buildSecretKeyRingsByEmailsUri(String emails) { @@ -157,9 +152,9 @@ public class ApgContract { return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_KEYS).build(); } - public static Uri buildPublicKeysRankUri(String keyRingRowId) { + public static Uri buildPublicKeysUri(String keyRingRowId, String keyRowId) { return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_KEYS) - .appendPath(PATH_RANK).build(); + .appendPath(keyRowId).build(); } } @@ -177,9 +172,9 @@ public class ApgContract { return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_KEYS).build(); } - public static Uri buildSecretKeysRankUri(String keyRingRowId) { + public static Uri buildSecretKeysUri(String keyRingRowId, String keyRowId) { return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_KEYS) - .appendPath(PATH_RANK).build(); + .appendPath(keyRowId).build(); } } @@ -198,9 +193,9 @@ public class ApgContract { .build(); } - public static Uri buildPublicUserIdsRankUri(String keyRingRowId) { + public static Uri buildPublicUserIdsUri(String keyRingRowId, String userIdRowId) { return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_USER_IDS) - .appendPath(PATH_RANK).build(); + .appendPath(userIdRowId).build(); } } @@ -219,9 +214,9 @@ public class ApgContract { .build(); } - public static Uri buildSecretUserIdsRankUri(String keyRingRowId) { + public static Uri buildSecretUserIdsUri(String keyRingRowId, String userIdRowId) { return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_USER_IDS) - .appendPath(PATH_RANK).build(); + .appendPath(userIdRowId).build(); } } diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ApgDatabase.java b/org_apg/src/org/thialfihar/android/apg/provider/ApgDatabase.java index b70cfa7b6..050320cb6 100644 --- a/org_apg/src/org/thialfihar/android/apg/provider/ApgDatabase.java +++ b/org_apg/src/org/thialfihar/android/apg/provider/ApgDatabase.java @@ -30,80 +30,40 @@ import android.provider.BaseColumns; import org.thialfihar.android.apg.util.Log; public class ApgDatabase extends SQLiteOpenHelper { - // APG1: "apg" private static final String DATABASE_NAME = "apg.db"; - // APG1: 2 private static final int DATABASE_VERSION = 3; public interface Tables { String KEY_RINGS = "key_rings"; String KEYS = "keys"; - String USERS = "user_ids"; + String USER_IDS = "user_ids"; } - // APG1: REFERENCES where not implemented private static final String CREATE_KEY_RINGS = "CREATE TABLE IF NOT EXISTS " + Tables.KEY_RINGS - + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY, " + KeyRingsColumns.MASTER_KEY_ROW_ID - + " INT64, " + KeyRingsColumns.TYPE + " INTEGER, " + KeyRingsColumns.WHO_ID - + " INTEGER, " + KeyRingsColumns.KEY_RING_DATA + " BLOB)"; + + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + KeyRingsColumns.MASTER_KEY_ID + " INT64, " + KeyRingsColumns.TYPE + " INTEGER, " + + KeyRingsColumns.KEY_RING_DATA + " BLOB)"; private static final String CREATE_KEYS = "CREATE TABLE IF NOT EXISTS " + Tables.KEYS + " (" - + BaseColumns._ID + " INTEGER PRIMARY KEY, " + KeysColumns.KEY_ID + " INT64, " - + KeysColumns.TYPE + " INTEGER, " + KeysColumns.IS_MASTER_KEY + " INTEGER, " - + KeysColumns.ALGORITHM + " INTEGER, " + KeysColumns.KEY_SIZE + " INTEGER, " - + KeysColumns.CAN_SIGN + " INTEGER, " + KeysColumns.CAN_ENCRYPT + " INTEGER, " - + KeysColumns.IS_REVOKED + " INTEGER, " + KeysColumns.CREATION + " INTEGER, " - + KeysColumns.EXPIRY + " INTEGER, " + KeysColumns.KEY_RING_ROW_ID + + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + KeysColumns.KEY_ID + + " INT64, " + KeysColumns.TYPE + " INTEGER, " + KeysColumns.IS_MASTER_KEY + + " INTEGER, " + KeysColumns.ALGORITHM + " INTEGER, " + KeysColumns.KEY_SIZE + + " INTEGER, " + KeysColumns.CAN_SIGN + " INTEGER, " + KeysColumns.CAN_ENCRYPT + + " INTEGER, " + KeysColumns.IS_REVOKED + " INTEGER, " + KeysColumns.CREATION + + " INTEGER, " + KeysColumns.EXPIRY + " INTEGER, " + KeysColumns.KEY_RING_ROW_ID + " INTEGER REFERENCES " + Tables.KEY_RINGS + " ON DELETE CASCADE, " + KeysColumns.KEY_DATA + " BLOB," + KeysColumns.RANK + " INTEGER)"; - private static final String CREATE_USER_IDS = "CREATE TABLE IF NOT EXISTS " + Tables.USERS - + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY, " + UserIdsColumns.KEY_ROW_ID - + " INTEGER REFERENCES " + Tables.KEYS + " ON DELETE CASCADE, " - + UserIdsColumns.USER_ID + " TEXT, " + UserIdsColumns.RANK + " INTEGER)"; + private static final String CREATE_USER_IDS = "CREATE TABLE IF NOT EXISTS " + Tables.USER_IDS + + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + UserIdsColumns.KEY_RING_ROW_ID + " INTEGER REFERENCES " + Tables.KEY_RINGS + + " ON DELETE CASCADE, " + UserIdsColumns.USER_ID + " TEXT, " + UserIdsColumns.RANK + + " INTEGER)"; ApgDatabase(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } - // - // public static HashMap<String, String> sKeyRingsProjection; - // public static HashMap<String, String> sKeysProjection; - // public static HashMap<String, String> sUserIdsProjection; - // - // private SQLiteDatabase mDb = null; - // private int mStatus = 0; - // - // static { - // sKeyRingsProjection = new HashMap<String, String>(); - // sKeyRingsProjection.put(KeyRings._ID, KeyRings._ID); - // sKeyRingsProjection.put(KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID); - // sKeyRingsProjection.put(KeyRings.TYPE, KeyRings.TYPE); - // sKeyRingsProjection.put(KeyRings.WHO_ID, KeyRings.WHO_ID); - // sKeyRingsProjection.put(KeyRings.KEY_RING_DATA, KeyRings.KEY_RING_DATA); - // - // sKeysProjection = new HashMap<String, String>(); - // sKeysProjection.put(Keys._ID, Keys._ID); - // sKeysProjection.put(Keys.KEY_ID, Keys.KEY_ID); - // sKeysProjection.put(Keys.TYPE, Keys.TYPE); - // sKeysProjection.put(Keys.IS_MASTER_KEY, Keys.IS_MASTER_KEY); - // sKeysProjection.put(Keys.ALGORITHM, Keys.ALGORITHM); - // sKeysProjection.put(Keys.KEY_SIZE, Keys.KEY_SIZE); - // sKeysProjection.put(Keys.CAN_SIGN, Keys.CAN_SIGN); - // sKeysProjection.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT); - // sKeysProjection.put(Keys.IS_REVOKED, Keys.IS_REVOKED); - // sKeysProjection.put(Keys.CREATION, Keys.CREATION); - // sKeysProjection.put(Keys.EXPIRY, Keys.EXPIRY); - // sKeysProjection.put(Keys.KEY_DATA, Keys.KEY_DATA); - // sKeysProjection.put(Keys.RANK, Keys.RANK); - // - // sUserIdsProjection = new HashMap<String, String>(); - // sUserIdsProjection.put(UserIds._ID, UserIds._ID); - // sUserIdsProjection.put(UserIds.KEY_ID, UserIds.KEY_ID); - // sUserIdsProjection.put(UserIds.USER_ID, UserIds.USER_ID); - // sUserIdsProjection.put(UserIds.RANK, UserIds.RANK); - // } - @Override public void onCreate(SQLiteDatabase db) { Log.w(Constants.TAG, "Creating database..."); diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ApgProvider.java b/org_apg/src/org/thialfihar/android/apg/provider/ApgProvider.java index 06d07fe5e..fce03600d 100644 --- a/org_apg/src/org/thialfihar/android/apg/provider/ApgProvider.java +++ b/org_apg/src/org/thialfihar/android/apg/provider/ApgProvider.java @@ -54,22 +54,28 @@ public class ApgProvider extends ContentProvider { private static final UriMatcher sUriMatcher = buildUriMatcher(); private static final int PUBLIC_KEY_RING = 101; - private static final int PUBLIC_KEY_RING_ROW_ID = 102; - private static final int PUBLIC_KEY_RING_BY_KEY_ID = 103; // TODO: Is this row id??? - private static final int PUBLIC_KEY_RING_BY_EMAILS = 104; + private static final int PUBLIC_KEY_RING_BY_ROW_ID = 102; + private static final int PUBLIC_KEY_RING_BY_MASTER_KEY_ID = 103; + private static final int PUBLIC_KEY_RING_BY_KEY_ID = 104; + private static final int PUBLIC_KEY_RING_BY_EMAILS = 105; + private static final int PUBLIC_KEY_RING_KEY = 111; - private static final int PUBLIC_KEY_RING_KEY_RANK = 112; + private static final int PUBLIC_KEY_RING_KEY_BY_ROW_ID = 112; + private static final int PUBLIC_KEY_RING_USER_ID = 121; - private static final int PUBLIC_KEY_RING_USER_ID_RANK = 122; + private static final int PUBLIC_KEY_RING_USER_ID_BY_ROW_ID = 122; private static final int SECRET_KEY_RING = 201; - private static final int SECRET_KEY_RING_ROW_ID = 202; - private static final int SECRET_KEY_RING_BY_KEY_ID = 203; - private static final int SECRET_KEY_RING_BY_EMAILS = 204; + private static final int SECRET_KEY_RING_BY_ROW_ID = 202; + private static final int SECRET_KEY_RING_BY_MASTER_KEY_ID = 203; + private static final int SECRET_KEY_RING_BY_KEY_ID = 204; + private static final int SECRET_KEY_RING_BY_EMAILS = 205; + private static final int SECRET_KEY_RING_KEY = 211; - private static final int SECRET_KEY_RING_KEY_RANK = 212; + private static final int SECRET_KEY_RING_KEY_BY_ROW_ID = 212; + private static final int SECRET_KEY_RING_USER_ID = 221; - private static final int SECRET_KEY_RING_USER_ID_RANK = 222; + private static final int SECRET_KEY_RING_USER_ID_BY_ROW_ID = 222; private static final int DATA_STREAM = 301; @@ -86,7 +92,8 @@ public class ApgProvider extends ContentProvider { * * <pre> * key_rings/public - * key_rings/public/_ + * key_rings/public/# + * key_rings/public/master_key_id/_ * key_rings/public/key_id/_ * key_rings/public/emails/_ * </pre> @@ -94,8 +101,10 @@ public class ApgProvider extends ContentProvider { matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC, PUBLIC_KEY_RING); matcher.addURI(authority, - ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + "/*", - PUBLIC_KEY_RING_ROW_ID); + ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + "/#", + PUBLIC_KEY_RING_BY_ROW_ID); + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + "/" + + ApgContract.PATH_BY_MASTER_KEY_ID + "/*", PUBLIC_KEY_RING_BY_MASTER_KEY_ID); matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + "/" + ApgContract.PATH_BY_KEY_ID + "/*", PUBLIC_KEY_RING_BY_KEY_ID); matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + "/" @@ -105,45 +114,46 @@ public class ApgProvider extends ContentProvider { * public keys * * <pre> - * key_rings/public/_/keys - * key_rings/public/_/keys/# + * key_rings/public/#/keys + * key_rings/public/#/keys/# * </pre> */ matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC - + "/*/" + ApgContract.PATH_KEYS, PUBLIC_KEY_RING_KEY); + + "/#/" + ApgContract.PATH_KEYS, PUBLIC_KEY_RING_KEY); matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC - + "/*/" + ApgContract.PATH_KEYS + "/" + ApgContract.PATH_RANK, - PUBLIC_KEY_RING_KEY_RANK); + + "/#/" + ApgContract.PATH_KEYS + "/#", PUBLIC_KEY_RING_KEY_BY_ROW_ID); /** * public user ids * * <pre> - * key_rings/public/_/user_ids - * key_rings/public/_/user_ids/# + * key_rings/public/#/user_ids + * key_rings/public/#/user_ids/# * </pre> */ matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC - + "/*/" + ApgContract.PATH_USER_IDS, PUBLIC_KEY_RING_USER_ID); + + "/#/" + ApgContract.PATH_USER_IDS, PUBLIC_KEY_RING_USER_ID); matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC - + "/*/" + ApgContract.PATH_USER_IDS + "/" + ApgContract.PATH_RANK, - PUBLIC_KEY_RING_USER_ID_RANK); + + "/#/" + ApgContract.PATH_USER_IDS + "/#", PUBLIC_KEY_RING_USER_ID_BY_ROW_ID); /** * secret key rings * * <pre> * key_rings/secret - * key_rings/secret/* - * key_rings/secret/key_id/* - * key_rings/secret/emails/* + * key_rings/secret/# + * key_rings/secret/master_key_id/_ + * key_rings/secret/key_id/_ + * key_rings/secret/emails/_ * </pre> */ matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET, SECRET_KEY_RING); matcher.addURI(authority, - ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + "/*", - SECRET_KEY_RING_ROW_ID); + ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + "/#", + SECRET_KEY_RING_BY_ROW_ID); + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + "/" + + ApgContract.PATH_BY_MASTER_KEY_ID + "/*", SECRET_KEY_RING_BY_MASTER_KEY_ID); matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + "/" + ApgContract.PATH_BY_KEY_ID + "/*", SECRET_KEY_RING_BY_KEY_ID); matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + "/" @@ -153,29 +163,27 @@ public class ApgProvider extends ContentProvider { * secret keys * * <pre> - * key_rings/secret/_/keys - * key_rings/secret/_/keys/# + * key_rings/secret/#/keys + * key_rings/secret/#/keys/# * </pre> */ matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET - + "/*/" + ApgContract.PATH_KEYS, SECRET_KEY_RING_KEY); + + "/#/" + ApgContract.PATH_KEYS, SECRET_KEY_RING_KEY); matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET - + "/*/" + ApgContract.PATH_KEYS + "/" + ApgContract.PATH_RANK, - SECRET_KEY_RING_KEY_RANK); + + "/#/" + ApgContract.PATH_KEYS + "/#", SECRET_KEY_RING_KEY_BY_ROW_ID); /** * secret user ids * * <pre> - * key_rings/secret/_/user_ids - * key_rings/secret/_/user_ids/# + * key_rings/secret/#/user_ids + * key_rings/secret/#/user_ids/# * </pre> */ matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET - + "/*/" + ApgContract.PATH_USER_IDS, SECRET_KEY_RING_USER_ID); + + "/#/" + ApgContract.PATH_USER_IDS, SECRET_KEY_RING_USER_ID); matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET - + "/*/" + ApgContract.PATH_USER_IDS + "/" + ApgContract.PATH_RANK, - SECRET_KEY_RING_USER_ID_RANK); + + "/#/" + ApgContract.PATH_USER_IDS + "/#", SECRET_KEY_RING_USER_ID_BY_ROW_ID); /** * data stream @@ -208,40 +216,42 @@ public class ApgProvider extends ContentProvider { case PUBLIC_KEY_RING_BY_EMAILS: return PublicKeyRings.CONTENT_TYPE; - case PUBLIC_KEY_RING_ROW_ID: + case PUBLIC_KEY_RING_BY_ROW_ID: + case PUBLIC_KEY_RING_BY_MASTER_KEY_ID: case PUBLIC_KEY_RING_BY_KEY_ID: return PublicKeyRings.CONTENT_ITEM_TYPE; case PUBLIC_KEY_RING_KEY: return PublicKeys.CONTENT_TYPE; - case PUBLIC_KEY_RING_KEY_RANK: + case PUBLIC_KEY_RING_KEY_BY_ROW_ID: return PublicKeys.CONTENT_ITEM_TYPE; case PUBLIC_KEY_RING_USER_ID: return PublicUserIds.CONTENT_TYPE; - case PUBLIC_KEY_RING_USER_ID_RANK: + case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID: return PublicUserIds.CONTENT_ITEM_TYPE; case SECRET_KEY_RING: case SECRET_KEY_RING_BY_EMAILS: return SecretKeyRings.CONTENT_TYPE; - case SECRET_KEY_RING_ROW_ID: + case SECRET_KEY_RING_BY_ROW_ID: + case SECRET_KEY_RING_BY_MASTER_KEY_ID: case SECRET_KEY_RING_BY_KEY_ID: return SecretKeyRings.CONTENT_ITEM_TYPE; case SECRET_KEY_RING_KEY: return SecretKeys.CONTENT_TYPE; - case SECRET_KEY_RING_KEY_RANK: + case SECRET_KEY_RING_KEY_BY_ROW_ID: return SecretKeys.CONTENT_ITEM_TYPE; case SECRET_KEY_RING_USER_ID: return SecretUserIds.CONTENT_TYPE; - case SECRET_KEY_RING_USER_ID_RANK: + case SECRET_KEY_RING_USER_ID_BY_ROW_ID: return SecretUserIds.CONTENT_ITEM_TYPE; default: @@ -259,24 +269,24 @@ public class ApgProvider extends ContentProvider { int type; switch (match) { case PUBLIC_KEY_RING: - case PUBLIC_KEY_RING_ROW_ID: + case PUBLIC_KEY_RING_BY_MASTER_KEY_ID: case PUBLIC_KEY_RING_BY_KEY_ID: case PUBLIC_KEY_RING_BY_EMAILS: case PUBLIC_KEY_RING_KEY: - case PUBLIC_KEY_RING_KEY_RANK: + case PUBLIC_KEY_RING_KEY_BY_ROW_ID: case PUBLIC_KEY_RING_USER_ID: - case PUBLIC_KEY_RING_USER_ID_RANK: + case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID: type = KeyTypes.PUBLIC; break; case SECRET_KEY_RING: - case SECRET_KEY_RING_ROW_ID: + case SECRET_KEY_RING_BY_MASTER_KEY_ID: case SECRET_KEY_RING_BY_KEY_ID: case SECRET_KEY_RING_BY_EMAILS: case SECRET_KEY_RING_KEY: - case SECRET_KEY_RING_KEY_RANK: + case SECRET_KEY_RING_KEY_BY_ROW_ID: case SECRET_KEY_RING_USER_ID: - case SECRET_KEY_RING_USER_ID_RANK: + case SECRET_KEY_RING_USER_ID_BY_ROW_ID: type = KeyTypes.SECRET; break; @@ -301,76 +311,93 @@ public class ApgProvider extends ContentProvider { int match = sUriMatcher.match(uri); - qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = " + getKeyType(match)); - switch (match) { - case PUBLIC_KEY_RING_ROW_ID: - case SECRET_KEY_RING_ROW_ID: - qb.appendWhere(" AND " + Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ROW_ID - + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(2)); + case PUBLIC_KEY_RING_BY_ROW_ID: + case SECRET_KEY_RING_BY_ROW_ID: + qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = " + + getKeyType(match)); + + qb.appendWhere(Tables.KEY_RINGS + "." + BaseColumns._ID + " = "); + qb.appendWhereEscapeString(uri.getLastPathSegment()); + + // break omitted intentionally + + case PUBLIC_KEY_RING_BY_MASTER_KEY_ID: + case SECRET_KEY_RING_BY_MASTER_KEY_ID: + qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID + " = "); + qb.appendWhereEscapeString(uri.getLastPathSegment()); // break omitted intentionally case PUBLIC_KEY_RING: case SECRET_KEY_RING: + qb.setTables(Tables.KEY_RINGS + " INNER JOIN " + Tables.KEYS + " ON " + "(" + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.KEYS + "." + KeysColumns.KEY_RING_ROW_ID + " AND " + Tables.KEYS + "." - + KeysColumns.IS_MASTER_KEY + " = '1'" + ") " + " INNER JOIN " + Tables.USERS - + " ON " + "(" + Tables.KEYS + "." + BaseColumns._ID + " = " + Tables.USERS - + "." + UserIdsColumns.KEY_ROW_ID + " AND " + Tables.USERS + "." - + UserIdsColumns.RANK + " = '0') "); + + KeysColumns.IS_MASTER_KEY + " = '1'" + ") " + " INNER JOIN " + + Tables.USER_IDS + " ON " + "(" + Tables.KEYS + "." + BaseColumns._ID + " = " + + Tables.USER_IDS + "." + UserIdsColumns.KEY_RING_ROW_ID + " AND " + + Tables.USER_IDS + "." + UserIdsColumns.RANK + " = '0') "); projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID); - projectionMap.put(KeyRingsColumns.MASTER_KEY_ROW_ID, Tables.KEY_RINGS + "." - + KeyRingsColumns.MASTER_KEY_ROW_ID); - projectionMap.put(UserIdsColumns.USER_ID, Tables.USERS + "." + UserIdsColumns.USER_ID); + projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." + + KeyRingsColumns.MASTER_KEY_ID); + projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + + UserIdsColumns.USER_ID); if (TextUtils.isEmpty(sortOrder)) { - sortOrder = Tables.USERS + "." + UserIdsColumns.USER_ID + " ASC"; + sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC"; } break; case SECRET_KEY_RING_BY_KEY_ID: case PUBLIC_KEY_RING_BY_KEY_ID: + qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = " + + getKeyType(match)); + qb.setTables(Tables.KEYS + " AS tmp INNER JOIN " + Tables.KEY_RINGS + " ON (" + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + "tmp." + KeysColumns.KEY_RING_ROW_ID + ")" + " INNER JOIN " + Tables.KEYS + " ON " + "(" + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.KEYS + "." + KeysColumns.KEY_RING_ROW_ID + " AND " + Tables.KEYS + "." - + KeysColumns.IS_MASTER_KEY + " = '1'" + ") " + " INNER JOIN " + Tables.USERS - + " ON " + "(" + Tables.KEYS + "." + BaseColumns._ID + " = " + Tables.USERS - + "." + UserIdsColumns.KEY_ROW_ID + " AND " + Tables.USERS + "." - + UserIdsColumns.RANK + " = '0') "); + + KeysColumns.IS_MASTER_KEY + " = '1'" + ") " + " INNER JOIN " + + Tables.USER_IDS + " ON " + "(" + Tables.KEYS + "." + BaseColumns._ID + " = " + + Tables.USER_IDS + "." + UserIdsColumns.KEY_RING_ROW_ID + " AND " + + Tables.USER_IDS + "." + UserIdsColumns.RANK + " = '0') "); projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID); - projectionMap.put(KeyRingsColumns.MASTER_KEY_ROW_ID, Tables.KEY_RINGS + "." - + KeyRingsColumns.MASTER_KEY_ROW_ID); - projectionMap.put(UserIdsColumns.USER_ID, Tables.USERS + "." + UserIdsColumns.USER_ID); + projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." + + KeyRingsColumns.MASTER_KEY_ID); + projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + + UserIdsColumns.USER_ID); - qb.appendWhere(" AND tmp." + KeysColumns.KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(3)); + qb.appendWhere("tmp." + KeysColumns.KEY_ID + " = "); + qb.appendWhereEscapeString(uri.getLastPathSegment()); break; case SECRET_KEY_RING_BY_EMAILS: case PUBLIC_KEY_RING_BY_EMAILS: + qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = " + + getKeyType(match)); + qb.setTables(Tables.KEY_RINGS + " INNER JOIN " + Tables.KEYS + " ON " + "(" + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.KEYS + "." + KeysColumns.KEY_RING_ROW_ID + " AND " + Tables.KEYS + "." - + KeysColumns.IS_MASTER_KEY + " = '1'" + ") " + " INNER JOIN " + Tables.USERS - + " ON " + "(" + Tables.KEYS + "." + BaseColumns._ID + " = " + Tables.USERS - + "." + UserIdsColumns.KEY_ROW_ID + " AND " + Tables.USERS + "." - + UserIdsColumns.RANK + " = '0') "); + + KeysColumns.IS_MASTER_KEY + " = '1'" + ") " + " INNER JOIN " + + Tables.USER_IDS + " ON " + "(" + Tables.KEYS + "." + BaseColumns._ID + " = " + + Tables.USER_IDS + "." + UserIdsColumns.KEY_RING_ROW_ID + " AND " + + Tables.USER_IDS + "." + UserIdsColumns.RANK + " = '0') "); projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID); - projectionMap.put(KeyRingsColumns.MASTER_KEY_ROW_ID, Tables.KEY_RINGS + "." - + KeyRingsColumns.MASTER_KEY_ROW_ID); - projectionMap.put(UserIdsColumns.USER_ID, Tables.USERS + "." + UserIdsColumns.USER_ID); + projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." + + KeyRingsColumns.MASTER_KEY_ID); + projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + + UserIdsColumns.USER_ID); - String emails = uri.getPathSegments().get(3); + String emails = uri.getLastPathSegment(); String chunks[] = emails.split(" *, *"); boolean gotCondition = false; String emailWhere = ""; @@ -388,13 +415,46 @@ public class ApgProvider extends ContentProvider { } if (gotCondition) { - qb.appendWhere(" AND EXISTS (SELECT tmp." + BaseColumns._ID + " FROM " - + Tables.USERS + " AS tmp WHERE tmp." + UserIdsColumns.KEY_ROW_ID + " = " + qb.appendWhere("EXISTS (SELECT tmp." + BaseColumns._ID + " FROM " + Tables.USER_IDS + + " AS tmp WHERE tmp." + UserIdsColumns.KEY_RING_ROW_ID + " = " + Tables.KEYS + "." + BaseColumns._ID + " AND (" + emailWhere + "))"); } break; + case PUBLIC_KEY_RING_KEY_BY_ROW_ID: + case SECRET_KEY_RING_KEY_BY_ROW_ID: + String keyRowId = uri.getLastPathSegment(); + qb.appendWhere(BaseColumns._ID + " = " + keyRowId); + + // break omitted intentionally + + case PUBLIC_KEY_RING_KEY: + case SECRET_KEY_RING_KEY: + qb.setTables(Tables.KEYS); + qb.appendWhere(KeysColumns.TYPE + " = " + getKeyType(match)); + + String foreignKeyRingRowId = uri.getPathSegments().get(2); + qb.appendWhere(KeysColumns.KEY_RING_ROW_ID + " = " + foreignKeyRingRowId); + + break; + + case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID: + case SECRET_KEY_RING_USER_ID_BY_ROW_ID: + String userIdRowId = uri.getLastPathSegment(); + qb.appendWhere(BaseColumns._ID + " = " + userIdRowId); + + // break omitted intentionally + + case PUBLIC_KEY_RING_USER_ID: + case SECRET_KEY_RING_USER_ID: + qb.setTables(Tables.USER_IDS); + + String foreignKeyRowId = uri.getPathSegments().get(2); + qb.appendWhere(UserIdsColumns.KEY_RING_ROW_ID + " = " + foreignKeyRowId); + + break; + default: throw new IllegalArgumentException("Unknown URI " + uri); @@ -410,9 +470,6 @@ public class ApgProvider extends ContentProvider { orderBy = sortOrder; } - Log.d(Constants.TAG, - qb.buildQuery(projection, selection, selectionArgs, null, null, orderBy, null) - .replace("WHERE", "WHERE\n")); Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy); // Tell the cursor what uri to watch, so it knows when its source data changes @@ -448,7 +505,7 @@ public class ApgProvider extends ContentProvider { break; case PUBLIC_KEY_RING_USER_ID: - db.insertOrThrow(Tables.USERS, null, values); + db.insertOrThrow(Tables.USER_IDS, null, values); rowUri = PublicUserIds.buildPublicUserIdsUri(values.getAsString(PublicUserIds._ID)); break; @@ -468,7 +525,7 @@ public class ApgProvider extends ContentProvider { break; case SECRET_KEY_RING_USER_ID: - db.insertOrThrow(Tables.USERS, null, values); + db.insertOrThrow(Tables.USER_IDS, null, values); rowUri = SecretUserIds.buildSecretUserIdsUri(values.getAsString(SecretUserIds._ID)); break; @@ -496,16 +553,28 @@ public class ApgProvider extends ContentProvider { final int match = sUriMatcher.match(uri); switch (match) { - case PUBLIC_KEY_RING_ROW_ID: - // corresponding keys and userids are deleted by ON DELETE CASCADE + case PUBLIC_KEY_RING_BY_ROW_ID: + // corresponding keys and userIds are deleted by ON DELETE CASCADE count = db.delete(Tables.KEY_RINGS, - buildDefaultSelection(uri, KeyTypes.PUBLIC, selection), selectionArgs); + buildDefaultKeyRingsSelection(uri, KeyTypes.PUBLIC, selection), selectionArgs); break; - case SECRET_KEY_RING_ROW_ID: - // corresponding keys and userids are deleted by ON DELETE CASCADE + case SECRET_KEY_RING_BY_ROW_ID: + // corresponding keys and userIds are deleted by ON DELETE CASCADE count = db.delete(Tables.KEY_RINGS, - buildDefaultSelection(uri, KeyTypes.SECRET, selection), selectionArgs); + buildDefaultKeyRingsSelection(uri, KeyTypes.SECRET, selection), selectionArgs); break; + case PUBLIC_KEY_RING_KEY_BY_ROW_ID: + count = db.delete(Tables.KEYS, + buildDefaultKeysSelection(uri, KeyTypes.PUBLIC, selection), selectionArgs); + case SECRET_KEY_RING_KEY_BY_ROW_ID: + count = db.delete(Tables.KEYS, + buildDefaultKeysSelection(uri, KeyTypes.SECRET, selection), selectionArgs); + case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID: + count = db.delete(Tables.KEYS, buildDefaultUserIdsSelection(uri, selection), + selectionArgs); + case SECRET_KEY_RING_USER_ID_BY_ROW_ID: + count = db.delete(Tables.KEYS, buildDefaultUserIdsSelection(uri, selection), + selectionArgs); default: throw new UnsupportedOperationException("Unknown uri: " + uri); } @@ -527,13 +596,31 @@ public class ApgProvider extends ContentProvider { try { final int match = sUriMatcher.match(uri); switch (match) { - case PUBLIC_KEY_RING_ROW_ID: + case PUBLIC_KEY_RING_BY_ROW_ID: count = db.update(Tables.KEY_RINGS, values, - buildDefaultSelection(uri, KeyTypes.PUBLIC, selection), selectionArgs); + buildDefaultKeyRingsSelection(uri, KeyTypes.PUBLIC, selection), + selectionArgs); break; - case SECRET_KEY_RING_ROW_ID: + case SECRET_KEY_RING_BY_ROW_ID: count = db.update(Tables.KEY_RINGS, values, - buildDefaultSelection(uri, KeyTypes.SECRET, selection), selectionArgs); + buildDefaultKeyRingsSelection(uri, KeyTypes.SECRET, selection), + selectionArgs); + break; + case PUBLIC_KEY_RING_KEY_BY_ROW_ID: + count = db.update(Tables.KEYS, values, + buildDefaultKeysSelection(uri, KeyTypes.PUBLIC, selection), selectionArgs); + break; + case SECRET_KEY_RING_KEY_BY_ROW_ID: + count = db.update(Tables.KEYS, values, + buildDefaultKeysSelection(uri, KeyTypes.SECRET, selection), selectionArgs); + break; + case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID: + count = db.update(Tables.USER_IDS, values, + buildDefaultUserIdsSelection(uri, selection), selectionArgs); + break; + case SECRET_KEY_RING_USER_ID_BY_ROW_ID: + count = db.update(Tables.USER_IDS, values, + buildDefaultUserIdsSelection(uri, selection), selectionArgs); break; default: throw new UnsupportedOperationException("Unknown uri: " + uri); @@ -549,26 +636,78 @@ public class ApgProvider extends ContentProvider { } /** - * Build default selection statement. If no extra selection is specified only build where clause - * with rowId + * Build default selection statement for KeyRings. If no extra selection is specified only build + * where clause with rowId * * @param uri * @param selection * @return */ - private String buildDefaultSelection(Uri uri, Integer keyType, String selection) { - String rowId = uri.getPathSegments().get(1); - String andWhere = ""; + private String buildDefaultKeyRingsSelection(Uri uri, Integer keyType, String selection) { + String rowId = uri.getLastPathSegment(); + + String andType = ""; + if (keyType != null) { + andType = " AND " + KeyRingsColumns.TYPE + "=" + keyType; + } + + String andSelection = ""; if (!TextUtils.isEmpty(selection)) { - andWhere = " AND (" + selection + ")"; + andSelection = " AND (" + selection + ")"; } + return BaseColumns._ID + "=" + rowId + andType + andSelection; + } + + /** + * Build default selection statement for Keys. If no extra selection is specified only build + * where clause with rowId + * + * @param uri + * @param selection + * @return + */ + private String buildDefaultKeysSelection(Uri uri, Integer keyType, String selection) { + String rowId = uri.getLastPathSegment(); + + String foreignKeyRingRowId = uri.getPathSegments().get(2); + String andForeignKeyRing = " AND " + KeysColumns.KEY_RING_ROW_ID + " = " + + foreignKeyRingRowId; + String andType = ""; if (keyType != null) { - andType = " AND " + KeyRingsColumns.TYPE + "=" + keyType; + andType = " AND " + KeysColumns.TYPE + "=" + keyType; + } + + String andSelection = ""; + if (!TextUtils.isEmpty(selection)) { + andSelection = " AND (" + selection + ")"; + } + + return BaseColumns._ID + "=" + rowId + andForeignKeyRing + andType + andSelection; + } + + /** + * Build default selection statement for UserIds. If no extra selection is specified only build + * where clause with rowId + * + * @param uri + * @param selection + * @return + */ + private String buildDefaultUserIdsSelection(Uri uri, String selection) { + String rowId = uri.getLastPathSegment(); + + String foreignKeyRingRowId = uri.getPathSegments().get(2); + String andForeignKeyRing = " AND " + KeysColumns.KEY_RING_ROW_ID + " = " + + foreignKeyRingRowId; + + String andSelection = ""; + if (!TextUtils.isEmpty(selection)) { + andSelection = " AND (" + selection + ")"; } - return BaseColumns._ID + "=" + rowId + andType + andWhere; + return BaseColumns._ID + "=" + rowId + andForeignKeyRing + andSelection; } @Override @@ -577,7 +716,7 @@ public class ApgProvider extends ContentProvider { if (match != DATA_STREAM) { throw new FileNotFoundException(); } - String fileName = uri.getPathSegments().get(1); + String fileName = uri.getLastPathSegment(); File file = new File(getContext().getFilesDir().getAbsolutePath(), fileName); return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ProviderHelper.java b/org_apg/src/org/thialfihar/android/apg/provider/ProviderHelper.java index 00fe51a7b..e37049c7e 100644 --- a/org_apg/src/org/thialfihar/android/apg/provider/ProviderHelper.java +++ b/org_apg/src/org/thialfihar/android/apg/provider/ProviderHelper.java @@ -1,42 +1,108 @@ package org.thialfihar.android.apg.provider; import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; import java.util.Vector; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.thialfihar.android.apg.Constants; -import org.thialfihar.android.apg.Id; import org.thialfihar.android.apg.helper.PGPConversionHelper; import org.thialfihar.android.apg.helper.PGPHelper; -import org.thialfihar.android.apg.helper.PGPMain.ApgGeneralException; import org.thialfihar.android.apg.provider.ApgContract.PublicKeyRings; import org.thialfihar.android.apg.provider.ApgContract.PublicKeys; +import org.thialfihar.android.apg.provider.ApgContract.PublicUserIds; import org.thialfihar.android.apg.provider.ApgContract.SecretKeyRings; import org.thialfihar.android.apg.provider.ApgContract.SecretKeys; +import org.thialfihar.android.apg.provider.ApgContract.SecretUserIds; +import org.thialfihar.android.apg.util.IterableIterator; import org.thialfihar.android.apg.util.Log; +import android.content.ContentProviderOperation; import android.content.ContentResolver; -import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; +import android.content.OperationApplicationException; import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; import android.net.Uri; +import android.os.RemoteException; public class ProviderHelper { + // + // public static HashMap<String, String> sKeyRingsProjection; + // public static HashMap<String, String> sKeysProjection; + // public static HashMap<String, String> sUserIdsProjection; + // + // private SQLiteDatabase mDb = null; + // private int mStatus = 0; + // + // static { + // sKeyRingsProjection = new HashMap<String, String>(); + // sKeyRingsProjection.put(KeyRings._ID, KeyRings._ID); + // sKeyRingsProjection.put(KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID); + // sKeyRingsProjection.put(KeyRings.TYPE, KeyRings.TYPE); + // sKeyRingsProjection.put(KeyRings.WHO_ID, KeyRings.WHO_ID); + // sKeyRingsProjection.put(KeyRings.KEY_RING_DATA, KeyRings.KEY_RING_DATA); + // + // sKeysProjection = new HashMap<String, String>(); + // sKeysProjection.put(Keys._ID, Keys._ID); + // sKeysProjection.put(Keys.KEY_ID, Keys.KEY_ID); + // sKeysProjection.put(Keys.TYPE, Keys.TYPE); + // sKeysProjection.put(Keys.IS_MASTER_KEY, Keys.IS_MASTER_KEY); + // sKeysProjection.put(Keys.ALGORITHM, Keys.ALGORITHM); + // sKeysProjection.put(Keys.KEY_SIZE, Keys.KEY_SIZE); + // sKeysProjection.put(Keys.CAN_SIGN, Keys.CAN_SIGN); + // sKeysProjection.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT); + // sKeysProjection.put(Keys.IS_REVOKED, Keys.IS_REVOKED); + // sKeysProjection.put(Keys.CREATION, Keys.CREATION); + // sKeysProjection.put(Keys.EXPIRY, Keys.EXPIRY); + // sKeysProjection.put(Keys.KEY_DATA, Keys.KEY_DATA); + // sKeysProjection.put(Keys.RANK, Keys.RANK); + // + // sUserIdsProjection = new HashMap<String, String>(); + // sUserIdsProjection.put(UserIds._ID, UserIds._ID); + // sUserIdsProjection.put(UserIds.KEY_ID, UserIds.KEY_ID); + // sUserIdsProjection.put(UserIds.USER_ID, UserIds.USER_ID); + // sUserIdsProjection.put(UserIds.RANK, UserIds.RANK); + // } + /** - * Retrieves the actual PGPPublicKeyRing object from the database blob associated with the rowId + * Retrieves the actual PGPPublicKeyRing object from the database blob associated with the + * maserKeyId * * @param context - * @param rowId + * @param masterKeyId * @return */ + public static PGPPublicKeyRing getPGPPublicKeyRingByMasterKeyId(Context context, + long masterKeyId) { + Uri queryUri = PublicKeyRings.buildPublicKeyRingsByMasterKeyIdUri(Long + .toString(masterKeyId)); + Cursor cursor = context.getContentResolver() + .query(queryUri, new String[] { PublicKeyRings._ID, PublicKeyRings.KEY_RING_DATA }, + null, null, null); + + PGPPublicKeyRing keyRing = null; + if (cursor != null && cursor.moveToFirst()) { + int keyRingDataCol = cursor.getColumnIndex(PublicKeyRings.KEY_RING_DATA); + + byte[] data = cursor.getBlob(keyRingDataCol); + if (data != null) { + keyRing = PGPConversionHelper.BytesToPGPPublicKeyRing(data); + } + } + + if (cursor != null) { + cursor.close(); + } + + return keyRing; + } + public static PGPPublicKeyRing getPGPPublicKeyRing(Context context, long rowId) { Uri queryUri = PublicKeyRings.buildPublicKeyRingsUri(Long.toString(rowId)); Cursor cursor = context.getContentResolver() @@ -61,12 +127,38 @@ public class ProviderHelper { } /** - * Retrieves the actual PGPSecretKeyRing object from the database blob associated with the rowId + * Retrieves the actual PGPSecretKeyRing object from the database blob associated with the + * maserKeyId * * @param context - * @param rowId + * @param masterKeyId * @return */ + public static PGPSecretKeyRing getPGPSecretKeyRingByMasterKeyId(Context context, + long masterKeyId) { + Uri queryUri = SecretKeyRings.buildSecretKeyRingsByMasterKeyIdUri(Long + .toString(masterKeyId)); + Cursor cursor = context.getContentResolver() + .query(queryUri, new String[] { SecretKeyRings._ID, SecretKeyRings.KEY_RING_DATA }, + null, null, null); + + PGPSecretKeyRing keyRing = null; + if (cursor != null && cursor.moveToFirst()) { + int keyRingDataCol = cursor.getColumnIndex(SecretKeyRings.KEY_RING_DATA); + + byte[] data = cursor.getBlob(keyRingDataCol); + if (data != null) { + keyRing = PGPConversionHelper.BytesToPGPSecretKeyRing(data); + } + } + + if (cursor != null) { + cursor.close(); + } + + return keyRing; + } + public static PGPSecretKeyRing getPGPSecretKeyRing(Context context, long rowId) { Uri queryUri = SecretKeyRings.buildSecretKeyRingsUri(Long.toString(rowId)); Cursor cursor = context.getContentResolver() @@ -91,7 +183,7 @@ public class ProviderHelper { } public static PGPSecretKey getPGPSecretKey(Context context, long keyId) { - PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRing(context, keyId); + PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(context, keyId); if (keyRing == null) { return null; } @@ -99,7 +191,7 @@ public class ProviderHelper { } public static PGPPublicKey getPGPPublicKey(Context context, long keyId) { - PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRing(context, keyId); + PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRingByMasterKeyId(context, keyId); if (keyRing == null) { return null; } @@ -107,36 +199,221 @@ public class ProviderHelper { return keyRing.getPublicKey(keyId); } - // public static String getMainUserId(long keyRowId, int type) { - // Uri queryUri = SecretKeyRings.buildSecretKeyRingsUri(Long.toString(rowId)); - // Cursor cursor = context.getContentResolver() - // .query(queryUri, new String[] { SecretKeyRings._ID, SecretKeyRings.KEY_RING_DATA }, - // null, null, null); - - // SQLiteDatabase db = mDatabase.db(); - // Cursor c = db.query(Keys.TABLE_NAME + " INNER JOIN " + KeyRings.TABLE_NAME + " ON (" - // + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + Keys.TABLE_NAME + "." - // + Keys.KEY_RING_ID + ") " + " INNER JOIN " + Keys.TABLE_NAME + " AS masterKey ON (" - // + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + "masterKey." - // + Keys.KEY_RING_ID + " AND " + "masterKey." + Keys.IS_MASTER_KEY + " = '1') " - // + " INNER JOIN " + UserIds.TABLE_NAME + " ON (" + UserIds.TABLE_NAME + "." - // + UserIds.KEY_ID + " = " + "masterKey." + Keys._ID + " AND " + UserIds.TABLE_NAME - // + "." + UserIds.RANK + " = '0')", new String[] { UserIds.USER_ID }, Keys.TABLE_NAME - // + "." + Keys.KEY_ID + " = ? AND " + KeyRings.TABLE_NAME + "." + KeyRings.TYPE - // + " = ?", new String[] { "" + keyRowId, "" + type, }, null, null, null); - // String userId = ""; - // if (c != null && c.moveToFirst()) { - // do { - // userId = c.getString(0); - // } while (c.moveToNext()); - // } - // - // if (c != null) { - // c.close(); - // } - // - // return userId; - // } + /** + * Saves PGPPublicKeyRing with its keys and userIds in DB + * + * @param context + * @param keyRing + * @return + * @throws IOException + * @throws GeneralException + */ + public static void saveKeyRing(Context context, PGPPublicKeyRing keyRing) throws IOException { + PGPPublicKey masterKey = keyRing.getPublicKey(); + long masterKeyId = masterKey.getKeyID(); + + // delete old version of this keyRing, which also deletes all keys and userIds on cascade + Uri deleteUri = PublicKeyRings.buildPublicKeyRingsByMasterKeyIdUri(Long + .toString(masterKeyId)); + context.getContentResolver().delete(deleteUri, null, null); + + ContentValues values = new ContentValues(); + values.put(PublicKeyRings.MASTER_KEY_ID, masterKeyId); + values.put(PublicKeyRings.KEY_RING_DATA, keyRing.getEncoded()); + + // insert new version of this keyRing + Uri uri = PublicKeyRings.buildPublicKeyRingsByMasterKeyIdUri(values + .getAsString(PublicKeyRings.MASTER_KEY_ID)); + Uri insertedUri = context.getContentResolver().insert(uri, values); + long keyRingRowId = Long.getLong(insertedUri.getLastPathSegment()); + + // save all keys and userIds included in keyRing object in database + ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(); + + int rank = 0; + for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) { + operations.add(buildPublicKeyOperations(context, keyRingRowId, key, rank)); + ++rank; + } + + int userIdRank = 0; + for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) { + operations.add(buildPublicUserIdOperations(context, keyRingRowId, userId, userIdRank)); + ++userIdRank; + } + + try { + context.getContentResolver().applyBatch(ApgContract.CONTENT_AUTHORITY, operations); + } catch (RemoteException e) { + Log.e(Constants.TAG, "applyBatch failed!", e); + } catch (OperationApplicationException e) { + Log.e(Constants.TAG, "applyBatch failed!", e); + } + } + + /** + * Saves PGPSecretKeyRing with its keys and userIds in DB + * + * @param context + * @param keyRing + * @return + * @throws IOException + * @throws GeneralException + */ + public static void saveKeyRing(Context context, PGPSecretKeyRing keyRing) throws IOException { + PGPSecretKey masterKey = keyRing.getSecretKey(); + long masterKeyId = masterKey.getKeyID(); + + // delete old version of this keyRing, which also deletes all keys and userIds on cascade + Uri deleteUri = SecretKeyRings.buildSecretKeyRingsByMasterKeyIdUri(Long + .toString(masterKeyId)); + context.getContentResolver().delete(deleteUri, null, null); + + ContentValues values = new ContentValues(); + values.put(SecretKeyRings.MASTER_KEY_ID, masterKeyId); + values.put(SecretKeyRings.KEY_RING_DATA, keyRing.getEncoded()); + + // insert new version of this keyRing + Uri uri = SecretKeyRings.buildSecretKeyRingsByMasterKeyIdUri(values + .getAsString(SecretKeyRings.MASTER_KEY_ID)); + Uri insertedUri = context.getContentResolver().insert(uri, values); + long keyRingRowId = Long.getLong(insertedUri.getLastPathSegment()); + + // save all keys and userIds included in keyRing object in database + ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(); + + int rank = 0; + for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) { + operations.add(buildSecretKeyOperations(context, keyRingRowId, key, rank)); + ++rank; + } + + int userIdRank = 0; + for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) { + operations.add(buildSecretUserIdOperations(context, keyRingRowId, userId, userIdRank)); + ++userIdRank; + } + + try { + context.getContentResolver().applyBatch(ApgContract.CONTENT_AUTHORITY, operations); + } catch (RemoteException e) { + Log.e(Constants.TAG, "applyBatch failed!", e); + } catch (OperationApplicationException e) { + Log.e(Constants.TAG, "applyBatch failed!", e); + } + } + + /** + * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing + * + * @param context + * @param keyRingRowId + * @param key + * @param rank + * @return + * @throws IOException + */ + private static ContentProviderOperation buildPublicKeyOperations(Context context, + long keyRingRowId, PGPPublicKey key, int rank) throws IOException { + ContentValues values = new ContentValues(); + values.put(PublicKeys.KEY_ID, key.getKeyID()); + values.put(PublicKeys.IS_MASTER_KEY, key.isMasterKey()); + values.put(PublicKeys.ALGORITHM, key.getAlgorithm()); + values.put(PublicKeys.KEY_SIZE, key.getBitStrength()); + values.put(PublicKeys.CAN_SIGN, PGPHelper.isSigningKey(key)); + values.put(PublicKeys.CAN_ENCRYPT, PGPHelper.isEncryptionKey(key)); + values.put(PublicKeys.IS_REVOKED, key.isRevoked()); + values.put(PublicKeys.CREATION, PGPHelper.getCreationDate(key).getTime() / 1000); + Date expiryDate = PGPHelper.getExpiryDate(key); + if (expiryDate != null) { + values.put(PublicKeys.EXPIRY, expiryDate.getTime() / 1000); + } + values.put(PublicKeys.KEY_RING_ROW_ID, keyRingRowId); + values.put(PublicKeys.KEY_DATA, key.getEncoded()); + values.put(PublicKeys.RANK, rank); + + Uri uri = PublicKeys.buildPublicKeysUri(Long.toString(keyRingRowId)); + + return ContentProviderOperation.newInsert(uri).withValues(values).build(); + } + + /** + * Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing + * + * @param context + * @param keyRingRowId + * @param key + * @param rank + * @return + * @throws IOException + */ + private static ContentProviderOperation buildPublicUserIdOperations(Context context, + long keyRingRowId, String userId, int rank) { + ContentValues values = new ContentValues(); + values.put(PublicUserIds.KEY_RING_ROW_ID, keyRingRowId); + values.put(PublicUserIds.USER_ID, userId); + values.put(PublicUserIds.RANK, rank); + + Uri uri = PublicUserIds.buildPublicUserIdsUri(Long.toString(keyRingRowId)); + + return ContentProviderOperation.newInsert(uri).withValues(values).build(); + } + + /** + * Build ContentProviderOperation to add PGPSecretKey to database corresponding to a keyRing + * + * @param context + * @param keyRingRowId + * @param key + * @param rank + * @return + * @throws IOException + */ + private static ContentProviderOperation buildSecretKeyOperations(Context context, + long keyRingRowId, PGPSecretKey key, int rank) throws IOException { + ContentValues values = new ContentValues(); + values.put(SecretKeys.KEY_ID, key.getKeyID()); + values.put(SecretKeys.IS_MASTER_KEY, key.isMasterKey()); + values.put(SecretKeys.ALGORITHM, key.getPublicKey().getAlgorithm()); + values.put(SecretKeys.KEY_SIZE, key.getPublicKey().getBitStrength()); + values.put(SecretKeys.CAN_SIGN, PGPHelper.isSigningKey(key)); + values.put(SecretKeys.CAN_ENCRYPT, PGPHelper.isEncryptionKey(key)); + values.put(SecretKeys.IS_REVOKED, key.getPublicKey().isRevoked()); + values.put(SecretKeys.CREATION, PGPHelper.getCreationDate(key).getTime() / 1000); + Date expiryDate = PGPHelper.getExpiryDate(key); + if (expiryDate != null) { + values.put(SecretKeys.EXPIRY, expiryDate.getTime() / 1000); + } + values.put(SecretKeys.KEY_RING_ROW_ID, keyRingRowId); + values.put(SecretKeys.KEY_DATA, key.getEncoded()); + values.put(SecretKeys.RANK, rank); + + Uri uri = SecretKeys.buildSecretKeysUri(Long.toString(keyRingRowId)); + + return ContentProviderOperation.newInsert(uri).withValues(values).build(); + } + + /** + * Build ContentProviderOperation to add SecretUserIds to database corresponding to a keyRing + * + * @param context + * @param keyRingRowId + * @param key + * @param rank + * @return + * @throws IOException + */ + private static ContentProviderOperation buildSecretUserIdOperations(Context context, + long keyRingRowId, String userId, int rank) { + ContentValues values = new ContentValues(); + values.put(SecretUserIds.KEY_RING_ROW_ID, keyRingRowId); + values.put(SecretUserIds.USER_ID, userId); + values.put(SecretUserIds.RANK, rank); + + Uri uri = SecretUserIds.buildSecretUserIdsUri(Long.toString(keyRingRowId)); + + return ContentProviderOperation.newInsert(uri).withValues(values).build(); + } /** * Retrieves ids of all SecretKeyRings |