aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider
diff options
context:
space:
mode:
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider')
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java254
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java288
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java1163
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java2
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java796
6 files changed, 910 insertions, 1595 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
index 404c128a1..2b40300d7 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
@@ -19,46 +19,47 @@ package org.sufficientlysecure.keychain.provider;
import android.net.Uri;
import android.provider.BaseColumns;
+
import org.sufficientlysecure.keychain.Constants;
public class KeychainContract {
interface KeyRingsColumns {
String MASTER_KEY_ID = "master_key_id"; // not a database id
- String TYPE = "type"; // see KeyTypes
String KEY_RING_DATA = "key_ring_data"; // PGPPublicKeyRing / PGPSecretKeyRing blob
}
interface KeysColumns {
+ String MASTER_KEY_ID = "master_key_id"; // not a database id
+ String RANK = "rank";
+
String KEY_ID = "key_id"; // not a database id
- String TYPE = "type"; // see KeyTypes
- String IS_MASTER_KEY = "is_master_key";
String ALGORITHM = "algorithm";
+ String FINGERPRINT = "fingerprint";
+
String KEY_SIZE = "key_size";
- String CAN_CERTIFY = "can_certify";
String CAN_SIGN = "can_sign";
String CAN_ENCRYPT = "can_encrypt";
+ String CAN_CERTIFY = "can_certify";
String IS_REVOKED = "is_revoked";
+
String CREATION = "creation";
String EXPIRY = "expiry";
- 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";
- String FINGERPRINT = "fingerprint";
}
interface UserIdsColumns {
- String KEY_RING_ROW_ID = "key_ring_row_id"; // foreign key to key_rings._ID
+ String MASTER_KEY_ID = "master_key_id"; // foreign key to key_rings._ID
String USER_ID = "user_id"; // not a database id
- String RANK = "rank";
+ String RANK = "rank"; // ONLY used for sorting! no key, no nothing!
+ String IS_PRIMARY = "is_primary";
}
interface CertsColumns {
- String KEY_RING_ROW_ID = "key_ring_row_id"; // verified id, foreign key to key_rings._ID
+ String MASTER_KEY_ID = "master_key_id"; // verified id, foreign key to key_rings._ID
String RANK = "rank"; // rank of verified key
- String KEY_ID = "key_id"; // verified id, not a database id
String KEY_ID_CERTIFIER = "key_id_certifier"; // verifying id, not a database id
String CREATION = "creation";
+ String EXPIRY = "expiry";
String VERIFIED = "verified";
String KEY_DATA = "key_data"; // certification blob
}
@@ -66,10 +67,15 @@ public class KeychainContract {
interface ApiAppsColumns {
String PACKAGE_NAME = "package_name";
String PACKAGE_SIGNATURE = "package_signature";
+ }
+
+ interface ApiAppsAccountsColumns {
+ String ACCOUNT_NAME = "account_name";
String KEY_ID = "key_id"; // not a database id
String ENCRYPTION_ALGORITHM = "encryption_algorithm";
String HASH_ALORITHM = "hash_algorithm";
String COMPRESSION = "compression";
+ String PACKAGE_NAME = "package_name"; // foreign key to api_apps.package_name
}
public static final class KeyTypes {
@@ -85,97 +91,81 @@ public class KeychainContract {
public static final String BASE_KEY_RINGS = "key_rings";
public static final String BASE_DATA = "data";
- public static final String PATH_PUBLIC = "public";
- public static final String PATH_SECRET = "secret";
+ public static final String PATH_UNIFIED = "unified";
- 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_KEY_ROW_ID = "key_row_id";
- public static final String PATH_BY_CERTIFIER_ID = "certifier_id";
- public static final String PATH_BY_EMAILS = "emails";
- public static final String PATH_BY_LIKE_EMAIL = "like_email";
+ public static final String PATH_FIND = "find";
+ public static final String PATH_BY_EMAIL = "email";
+ public static final String PATH_BY_SUBKEY = "subkey";
+ public static final String PATH_PUBLIC = "public";
+ public static final String PATH_SECRET = "secret";
public static final String PATH_USER_IDS = "user_ids";
public static final String PATH_KEYS = "keys";
+ public static final String PATH_CERTS = "certs";
public static final String BASE_API_APPS = "api_apps";
- public static final String PATH_BY_PACKAGE_NAME = "package_name";
+ public static final String PATH_ACCOUNTS = "accounts";
- public static final String BASE_CERTS = "certs";
+ 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 class KeyRings implements KeyRingsColumns, BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_KEY_RINGS).build();
- /**
- * Use if multiple items get returned
- */
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.key_ring";
-
- /**
- * Use if a single item is returned
- */
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.key_ring";
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/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() {
- return CONTENT_URI;
+ return CONTENT_URI.buildUpon().appendPath(PATH_UNIFIED).build();
}
- public static Uri buildPublicKeyRingsUri() {
- return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).build();
+ public static Uri buildGenericKeyRingUri(String masterKeyId) {
+ return CONTENT_URI.buildUpon().appendPath(masterKeyId).build();
}
-
- public static Uri buildPublicKeyRingsUri(String keyRingRowId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).appendPath(keyRingRowId).build();
+ public static Uri buildUnifiedKeyRingUri(String masterKeyId) {
+ return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_UNIFIED).build();
}
-
- public static Uri buildPublicKeyRingsByMasterKeyIdUri(String masterKeyId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC)
- .appendPath(PATH_BY_MASTER_KEY_ID).appendPath(masterKeyId).build();
+ public static Uri buildUnifiedKeyRingUri(Uri uri) {
+ return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_UNIFIED).build();
}
- public static Uri buildPublicKeyRingsByKeyIdUri(String keyId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).appendPath(PATH_BY_KEY_ID)
- .appendPath(keyId).build();
+ public static Uri buildUnifiedKeyRingsFindByEmailUri(String email) {
+ return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_EMAIL).appendPath(email).build();
}
-
- public static Uri buildPublicKeyRingsByEmailsUri(String emails) {
- return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).appendPath(PATH_BY_EMAILS)
- .appendPath(emails).build();
+ public static Uri buildUnifiedKeyRingsFindBySubkeyUri(String subkey) {
+ return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_SUBKEY).appendPath(subkey).build();
}
- public static Uri buildPublicKeyRingsByLikeEmailUri(String emails) {
- return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).appendPath(PATH_BY_LIKE_EMAIL)
- .appendPath(emails).build();
- }
+ }
- public static Uri buildSecretKeyRingsUri() {
- return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).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 Uri buildSecretKeyRingsUri(String keyRingRowId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).appendPath(keyRingRowId).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 buildSecretKeyRingsByMasterKeyIdUri(String masterKeyId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_SECRET)
- .appendPath(PATH_BY_MASTER_KEY_ID).appendPath(masterKeyId).build();
+ public static Uri buildPublicKeyRingUri() {
+ return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).build();
}
-
- public static Uri buildSecretKeyRingsByKeyIdUri(String keyId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).appendPath(PATH_BY_KEY_ID)
- .appendPath(keyId).build();
+ public static Uri buildPublicKeyRingUri(String masterKeyId) {
+ return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_PUBLIC).build();
}
-
- public static Uri buildSecretKeyRingsByEmailsUri(String emails) {
- return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).appendPath(PATH_BY_EMAILS)
- .appendPath(emails).build();
+ public static Uri buildPublicKeyRingUri(Uri uri) {
+ return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_PUBLIC).build();
}
- public static Uri buildSecretKeyRingsByLikeEmails(String emails) {
- return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).appendPath(PATH_BY_LIKE_EMAIL)
- .appendPath(emails).build();
+ public static Uri buildSecretKeyRingUri() {
+ return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).build();
+ }
+ public static Uri buildSecretKeyRingUri(String masterKeyId) {
+ return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_SECRET).build();
+ }
+ public static Uri buildSecretKeyRingUri(Uri uri) {
+ return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_SECRET).build();
}
+
}
public static class Keys implements KeysColumns, BaseColumns {
@@ -185,131 +175,101 @@ public class KeychainContract {
/**
* Use if multiple items get returned
*/
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.key";
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key";
/**
* Use if a single item is returned
*/
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.key";
-
- public static Uri buildPublicKeysUri(String keyRingRowId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).appendPath(keyRingRowId)
- .appendPath(PATH_KEYS).build();
- }
-
- public static Uri buildPublicKeysUri(String keyRingRowId, String keyRowId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).appendPath(keyRingRowId)
- .appendPath(PATH_KEYS).appendPath(keyRowId).build();
- }
-
- public static Uri buildSecretKeysUri(String keyRingRowId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).appendPath(keyRingRowId)
- .appendPath(PATH_KEYS).build();
- }
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key";
- public static Uri buildSecretKeysUri(String keyRingRowId, String keyRowId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).appendPath(keyRingRowId)
- .appendPath(PATH_KEYS).appendPath(keyRowId).build();
+ public static Uri buildKeysUri(String masterKeyId) {
+ return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_KEYS).build();
}
-
- public static Uri buildKeysUri(Uri keyRingUri) {
- return keyRingUri.buildUpon().appendPath(PATH_KEYS).build();
+ public static Uri buildKeysUri(Uri uri) {
+ return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_KEYS).build();
}
- public static Uri buildKeysUri(Uri keyRingUri, String keyRowId) {
- return keyRingUri.buildUpon().appendPath(PATH_KEYS).appendPath(keyRowId).build();
- }
}
public static class UserIds implements UserIdsColumns, BaseColumns {
+ public static final String VERIFIED = "verified";
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_KEY_RINGS).build();
/**
* Use if multiple items get returned
*/
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.user_id";
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.user_id";
/**
* Use if a single item is returned
*/
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.user_id";
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.user_id";
- public static Uri buildPublicUserIdsUri(String keyRingRowId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).appendPath(keyRingRowId)
- .appendPath(PATH_USER_IDS).build();
+ public static Uri buildUserIdsUri(String masterKeyId) {
+ return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_USER_IDS).build();
}
-
- public static Uri buildPublicUserIdsUri(String keyRingRowId, String userIdRowId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).appendPath(keyRingRowId)
- .appendPath(PATH_USER_IDS).appendPath(userIdRowId).build();
+ public static Uri buildUserIdsUri(Uri uri) {
+ return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_USER_IDS).build();
}
+ }
- public static Uri buildSecretUserIdsUri(String keyRingRowId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).appendPath(keyRingRowId)
- .appendPath(PATH_USER_IDS).build();
- }
+ public static class ApiApps implements ApiAppsColumns, BaseColumns {
+ public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
+ .appendPath(BASE_API_APPS).build();
- public static Uri buildSecretUserIdsUri(String keyRingRowId, String userIdRowId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).appendPath(keyRingRowId)
- .appendPath(PATH_USER_IDS).appendPath(userIdRowId).build();
- }
+ /**
+ * Use if multiple items get returned
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.api_apps";
- public static Uri buildUserIdsUri(Uri keyRingUri) {
- return keyRingUri.buildUpon().appendPath(PATH_USER_IDS).build();
- }
+ /**
+ * Use if a single item is returned
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.api_app";
- public static Uri buildUserIdsUri(Uri keyRingUri, String userIdRowId) {
- return keyRingUri.buildUpon().appendPath(PATH_USER_IDS).appendPath(userIdRowId).build();
+ public static Uri buildByPackageNameUri(String packageName) {
+ return CONTENT_URI.buildUpon().appendEncodedPath(packageName).build();
}
}
- public static class ApiApps implements ApiAppsColumns, BaseColumns {
+ public static class ApiAccounts implements ApiAppsAccountsColumns, BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_API_APPS).build();
/**
* Use if multiple items get returned
*/
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.api_apps";
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.api_app.accounts";
/**
* Use if a single item is returned
*/
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.api_apps";
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.api_app.account";
- public static Uri buildIdUri(String rowId) {
- return CONTENT_URI.buildUpon().appendPath(rowId).build();
+ public static Uri buildBaseUri(String packageName) {
+ return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendPath(PATH_ACCOUNTS)
+ .build();
}
- public static Uri buildByPackageNameUri(String packageName) {
- return CONTENT_URI.buildUpon().appendPath(PATH_BY_PACKAGE_NAME).appendPath(packageName)
- .build();
+ public static Uri buildByPackageAndAccountUri(String packageName, String accountName) {
+ return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendPath(PATH_ACCOUNTS)
+ .appendEncodedPath(accountName).build();
}
}
public static class Certs implements CertsColumns, BaseColumns {
- public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
- .appendPath(BASE_CERTS).build();
+ public static final String USER_ID = UserIdsColumns.USER_ID;
+ public static final String SIGNER_UID = "signer_user_id";
- // do we even need this one...? just using it as default for database insert notifications~
- public static Uri buildCertsUri(String rowId) {
- return CONTENT_URI.buildUpon().appendPath(rowId).build();
- }
-
- public static Uri buildCertsByKeyRowIdUri(String keyRingRowId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_BY_KEY_ROW_ID)
- .appendPath(keyRingRowId).build();
- }
+ public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
+ .appendPath(BASE_KEY_RINGS).build();
- public static Uri buildCertsByKeyIdUri(String keyId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_BY_KEY_ID).appendPath(keyId)
- .build();
+ public static Uri buildCertsUri(String masterKeyId) {
+ return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_CERTS).build();
}
-
- public static Uri buildCertsByCertifierKeyIdUri(String keyId) {
- return CONTENT_URI.buildUpon().appendPath(PATH_BY_CERTIFIER_ID).appendPath(keyId)
- .build();
+ public static Uri buildCertsUri(Uri uri) {
+ return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_CERTS).build();
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index cc6a1f1e1..fda1783cb 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -18,97 +18,156 @@
package org.sufficientlysecure.keychain.provider;
import android.content.Context;
+import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
+
+import org.spongycastle.openpgp.PGPKeyRing;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
+import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns;
+import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsAccountsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.CertsColumns;
import org.sufficientlysecure.keychain.util.Log;
+import java.io.IOException;
+
public class KeychainDatabase extends SQLiteOpenHelper {
- private static final String DATABASE_NAME = "apg.db";
- private static final int DATABASE_VERSION = 8;
+ private static final String DATABASE_NAME = "openkeychain.db";
+ private static final int DATABASE_VERSION = 1;
+ static Boolean apg_hack = false;
public interface Tables {
- String KEY_RINGS = "key_rings";
+ String KEY_RINGS_PUBLIC = "keyrings_public";
+ String KEY_RINGS_SECRET = "keyrings_secret";
String KEYS = "keys";
String USER_IDS = "user_ids";
- String API_APPS = "api_apps";
String CERTS = "certs";
+ String API_APPS = "api_apps";
+ String API_ACCOUNTS = "api_accounts";
}
- private static final String CREATE_KEY_RINGS = "CREATE TABLE IF NOT EXISTS " + Tables.KEY_RINGS
- + " (" + 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 AUTOINCREMENT, "
- + KeysColumns.KEY_ID + " INT64, "
- + KeysColumns.TYPE + " INTEGER, "
- + KeysColumns.IS_MASTER_KEY + " INTEGER, "
- + KeysColumns.ALGORITHM + " INTEGER, "
- + KeysColumns.KEY_SIZE + " INTEGER, "
- + KeysColumns.CAN_CERTIFY + " INTEGER, "
- + KeysColumns.CAN_SIGN + " INTEGER, "
- + KeysColumns.CAN_ENCRYPT + " INTEGER, "
- + KeysColumns.IS_REVOKED + " INTEGER, "
- + KeysColumns.CREATION + " INTEGER, "
- + KeysColumns.EXPIRY + " INTEGER, "
- + KeysColumns.KEY_DATA + " BLOB,"
- + KeysColumns.RANK + " INTEGER, "
- + KeysColumns.FINGERPRINT + " BLOB, "
- + KeysColumns.KEY_RING_ROW_ID + " INTEGER NOT NULL, FOREIGN KEY("
- + KeysColumns.KEY_RING_ROW_ID + ") REFERENCES " + Tables.KEY_RINGS + "("
- + BaseColumns._ID + ") ON DELETE CASCADE)";
-
- private static final String CREATE_USER_IDS = "CREATE TABLE IF NOT EXISTS " + Tables.USER_IDS
- + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + UserIdsColumns.USER_ID + " TEXT, "
- + UserIdsColumns.RANK + " INTEGER, "
- + UserIdsColumns.KEY_RING_ROW_ID + " INTEGER NOT NULL, FOREIGN KEY("
- + UserIdsColumns.KEY_RING_ROW_ID + ") REFERENCES " + Tables.KEY_RINGS + "("
- + BaseColumns._ID + ") ON DELETE CASCADE)";
+ private static final String CREATE_KEYRINGS_PUBLIC =
+ "CREATE TABLE IF NOT EXISTS keyrings_public ("
+ + KeyRingsColumns.MASTER_KEY_ID + " INTEGER PRIMARY KEY,"
+ + KeyRingsColumns.KEY_RING_DATA + " BLOB"
+ + ")";
+
+ private static final String CREATE_KEYRINGS_SECRET =
+ "CREATE TABLE IF NOT EXISTS keyrings_secret ("
+ + KeyRingsColumns.MASTER_KEY_ID + " INTEGER PRIMARY KEY,"
+ + KeyRingsColumns.KEY_RING_DATA + " BLOB,"
+ + "FOREIGN KEY(" + KeyRingsColumns.MASTER_KEY_ID + ") "
+ + "REFERENCES keyrings_public(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
+ + ")";
+
+ private static final String CREATE_KEYS =
+ "CREATE TABLE IF NOT EXISTS " + Tables.KEYS + " ("
+ + KeysColumns.MASTER_KEY_ID + " INTEGER, "
+ + KeysColumns.RANK + " INTEGER, "
+
+ + KeysColumns.KEY_ID + " INTEGER, "
+ + KeysColumns.KEY_SIZE + " INTEGER, "
+ + KeysColumns.ALGORITHM + " INTEGER, "
+ + KeysColumns.FINGERPRINT + " BLOB, "
+
+ + KeysColumns.CAN_CERTIFY + " BOOLEAN, "
+ + KeysColumns.CAN_SIGN + " BOOLEAN, "
+ + KeysColumns.CAN_ENCRYPT + " BOOLEAN, "
+ + KeysColumns.IS_REVOKED + " BOOLEAN, "
+
+ + KeysColumns.CREATION + " INTEGER, "
+ + KeysColumns.EXPIRY + " INTEGER, "
+
+ + "PRIMARY KEY(" + KeysColumns.MASTER_KEY_ID + ", " + KeysColumns.RANK + "),"
+ + "FOREIGN KEY(" + KeysColumns.MASTER_KEY_ID + ") REFERENCES "
+ + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
+ + ")";
+
+ private static final String CREATE_USER_IDS =
+ "CREATE TABLE IF NOT EXISTS " + Tables.USER_IDS + "("
+ + UserIdsColumns.MASTER_KEY_ID + " INTEGER, "
+ + UserIdsColumns.USER_ID + " CHARMANDER, "
+
+ + UserIdsColumns.IS_PRIMARY + " BOOLEAN, "
+ + UserIdsColumns.RANK+ " INTEGER, "
+
+ + "PRIMARY KEY(" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.USER_ID + "), "
+ + "UNIQUE (" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.RANK + "), "
+ + "FOREIGN KEY(" + UserIdsColumns.MASTER_KEY_ID + ") REFERENCES "
+ + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
+ + ")";
+
+ private static final String CREATE_CERTS =
+ "CREATE TABLE IF NOT EXISTS " + Tables.CERTS + "("
+ + CertsColumns.MASTER_KEY_ID + " INTEGER,"
+ + CertsColumns.RANK + " INTEGER, " // rank of certified uid
+
+ + CertsColumns.KEY_ID_CERTIFIER + " INTEGER, " // certifying key
+ + CertsColumns.CREATION + " INTEGER, "
+ + CertsColumns.EXPIRY + " INTEGER, "
+ + CertsColumns.VERIFIED + " INTEGER, "
+
+ + CertsColumns.KEY_DATA + " BLOB,"
+ + "PRIMARY KEY(" + CertsColumns.MASTER_KEY_ID + ", " + CertsColumns.RANK + ", "
+ + CertsColumns.KEY_ID_CERTIFIER + "), "
+ + "FOREIGN KEY(" + CertsColumns.MASTER_KEY_ID + ") REFERENCES "
+ + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE,"
+ + "FOREIGN KEY(" + CertsColumns.MASTER_KEY_ID + ", " + CertsColumns.RANK + ") REFERENCES "
+ + Tables.USER_IDS + "(" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.RANK + ") ON DELETE CASCADE"
+ + ")";
private static final String CREATE_API_APPS = "CREATE TABLE IF NOT EXISTS " + Tables.API_APPS
+ " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + ApiAppsColumns.PACKAGE_NAME + " TEXT UNIQUE, "
- + ApiAppsColumns.PACKAGE_SIGNATURE + " BLOB, "
- + ApiAppsColumns.KEY_ID + " INT64, "
- + ApiAppsColumns.ENCRYPTION_ALGORITHM + " INTEGER, "
- + ApiAppsColumns.HASH_ALORITHM + " INTEGER, "
- + ApiAppsColumns.COMPRESSION + " INTEGER)";
-
- private static final String CREATE_CERTS = "CREATE TABLE IF NOT EXISTS " + Tables.CERTS
- + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + CertsColumns.KEY_RING_ROW_ID + " INTEGER NOT NULL "
- + " REFERENCES " + Tables.KEY_RINGS + "(" + BaseColumns._ID + ") ON DELETE CASCADE, "
- + CertsColumns.KEY_ID + " INTEGER, " // certified key
- + CertsColumns.RANK + " INTEGER, " // key rank of certified uid
- + CertsColumns.KEY_ID_CERTIFIER + " INTEGER, " // certifying key
- + CertsColumns.CREATION + " INTEGER, "
- + CertsColumns.VERIFIED + " INTEGER, "
- + CertsColumns.KEY_DATA + " BLOB)";
+ + ApiAppsColumns.PACKAGE_NAME + " TEXT NOT NULL UNIQUE, "
+ + ApiAppsColumns.PACKAGE_SIGNATURE + " BLOB)";
+ private static final String CREATE_API_APPS_ACCOUNTS = "CREATE TABLE IF NOT EXISTS " + Tables.API_ACCOUNTS
+ + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + ApiAppsAccountsColumns.ACCOUNT_NAME + " TEXT NOT NULL, "
+ + ApiAppsAccountsColumns.KEY_ID + " INT64, "
+ + ApiAppsAccountsColumns.ENCRYPTION_ALGORITHM + " INTEGER, "
+ + ApiAppsAccountsColumns.HASH_ALORITHM + " INTEGER, "
+ + ApiAppsAccountsColumns.COMPRESSION + " INTEGER, "
+ + ApiAppsAccountsColumns.PACKAGE_NAME + " TEXT NOT NULL, "
+ + "UNIQUE(" + ApiAppsAccountsColumns.ACCOUNT_NAME + ", "
+ + ApiAppsAccountsColumns.PACKAGE_NAME + "), "
+ + "FOREIGN KEY(" + ApiAppsAccountsColumns.PACKAGE_NAME + ") REFERENCES "
+ + Tables.API_APPS + "(" + ApiAppsColumns.PACKAGE_NAME + ") ON DELETE CASCADE)";
KeychainDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
+
+ // make sure this is only done once, on the first instance!
+ boolean iAmIt = false;
+ synchronized(apg_hack) {
+ if(!apg_hack) {
+ iAmIt = true;
+ apg_hack = true;
+ }
+ }
+ // if it's us, do the import
+ if(iAmIt)
+ checkAndImportApg(context);
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.w(Constants.TAG, "Creating database...");
- db.execSQL(CREATE_KEY_RINGS);
+ db.execSQL(CREATE_KEYRINGS_PUBLIC);
+ db.execSQL(CREATE_KEYRINGS_SECRET);
db.execSQL(CREATE_KEYS);
db.execSQL(CREATE_USER_IDS);
- db.execSQL(CREATE_API_APPS);
db.execSQL(CREATE_CERTS);
+ db.execSQL(CREATE_API_APPS);
+ db.execSQL(CREATE_API_APPS_ACCOUNTS);
}
@Override
@@ -117,47 +176,100 @@ public class KeychainDatabase extends SQLiteOpenHelper {
if (!db.isReadOnly()) {
// Enable foreign key constraints
db.execSQL("PRAGMA foreign_keys=ON;");
+ // TODO remove, once we remove the "always migrate" debug stuff
+ // db.execSQL("DROP TABLE certs;");
+ // db.execSQL("DROP TABLE user_ids;");
+ db.execSQL(CREATE_USER_IDS);
+ db.execSQL(CREATE_CERTS);
}
}
@Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- Log.w(Constants.TAG, "Upgrading database from version " + oldVersion + " to " + newVersion);
-
- // Upgrade from oldVersion through all cases to newest one
- for (int version = oldVersion; version < newVersion; ++version) {
- Log.w(Constants.TAG, "Upgrading database to version " + version);
-
- switch (version) {
- case 3:
- db.execSQL("ALTER TABLE " + Tables.KEYS + " ADD COLUMN " + KeysColumns.CAN_CERTIFY
- + " INTEGER DEFAULT 0;");
- db.execSQL("UPDATE " + Tables.KEYS + " SET " + KeysColumns.CAN_CERTIFY
- + " = 1 WHERE " + KeysColumns.IS_MASTER_KEY + "= 1;");
- break;
- case 4:
- db.execSQL(CREATE_API_APPS);
- break;
- case 5:
- // new column: package_signature
- db.execSQL("DROP TABLE IF EXISTS " + Tables.API_APPS);
- db.execSQL(CREATE_API_APPS);
- break;
- case 6:
- // new column: fingerprint
- db.execSQL("ALTER TABLE " + Tables.KEYS + " ADD COLUMN " + KeysColumns.FINGERPRINT
- + " BLOB;");
- break;
- case 7:
- // new table: certs
- db.execSQL(CREATE_CERTS);
+ public void onUpgrade(SQLiteDatabase db, int old, int nu) {
+ // don't care (this is version 1)
+ }
+ /** This method tries to import data from a provided database.
+ *
+ * The sole assumptions made on this db are that there is a key_rings table
+ * with a key_ring_data and a type column, the latter of which should be bigger
+ * for secret keys.
+ */
+ public void checkAndImportApg(Context context) {
+
+ boolean hasApgDb = false; {
+ // It's the Java way =(
+ String[] dbs = context.databaseList();
+ for(String db : dbs) {
+ if(db.equals("apg.db")) {
+ hasApgDb = true;
break;
- default:
- break;
+ }
+ }
+ }
+
+ if(!hasApgDb)
+ return;
+ Log.d(Constants.TAG, "apg.db exists! Importing...");
+
+ SQLiteDatabase db = new SQLiteOpenHelper(context, "apg.db", null, 1) {
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ // should never happen
+ assert false;
+ }
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int old, int nu) {
+ // don't care
+ }
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int old, int nu) {
+ // don't care either
}
+ }.getReadableDatabase();
+
+ // kill current!
+ { // TODO don't kill current.
+ Log.d(Constants.TAG, "Truncating db...");
+ SQLiteDatabase d = getWritableDatabase();
+ d.execSQL("DELETE FROM keyrings_public");
+ d.close();
+ Log.d(Constants.TAG, "Ok.");
}
+
+ Cursor c = db.rawQuery("SELECT key_ring_data FROM key_rings ORDER BY type ASC", null);
+ try {
+ // import from old database
+ Log.d(Constants.TAG, "Importing " + c.getCount() + " keyrings from apg.db...");
+ for(int i = 0; i < c.getCount(); i++) {
+ c.moveToPosition(i);
+ byte[] data = c.getBlob(0);
+ PGPKeyRing ring = PgpConversionHelper.BytesToPGPKeyRing(data);
+ if(ring instanceof PGPPublicKeyRing)
+ ProviderHelper.saveKeyRing(context, (PGPPublicKeyRing) ring);
+ else if(ring instanceof PGPSecretKeyRing)
+ ProviderHelper.saveKeyRing(context, (PGPSecretKeyRing) ring);
+ else {
+ Log.e(Constants.TAG, "Unknown blob data type!");
+ }
+ }
+
+ } catch(IOException e) {
+ Log.e(Constants.TAG, "Error importing apg db!", e);
+ return;
+ } finally {
+ if(c != null)
+ c.close();
+ if(db != null)
+ db.close();
+ }
+
+ // TODO delete old db, if we are sure this works
+ // context.deleteDatabase("apg.db");
+ Log.d(Constants.TAG, "All done, (not) deleting apg.db");
+
+
}
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
index f34423a71..83b3dd744 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,10 +26,16 @@ import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
-import android.provider.BaseColumns;
import android.text.TextUtils;
+
import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.provider.KeychainContract.*;
+import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts;
+import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
+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.Certs;
+import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.util.Log;
@@ -37,54 +43,29 @@ import java.util.Arrays;
import java.util.HashMap;
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 PUBLIC_KEY_RING = 101;
- 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_BY_LIKE_EMAIL = 106;
-
- private static final int PUBLIC_KEY_RING_KEY = 111;
- 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_BY_ROW_ID = 122;
- private static final int PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID = 123;
-
- private static final int SECRET_KEY_RING = 201;
- 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_BY_LIKE_EMAIL = 206;
-
- private static final int SECRET_KEY_RING_KEY = 211;
- 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_BY_ROW_ID = 222;
+
+ private static final int KEY_RINGS_UNIFIED = 101;
+ private static final int KEY_RINGS_PUBLIC = 102;
+ private static final int KEY_RINGS_SECRET = 103;
+
+ private static final int KEY_RING_UNIFIED = 200;
+ private static final int KEY_RING_KEYS = 201;
+ private static final int KEY_RING_USER_IDS = 202;
+ private static final int KEY_RING_PUBLIC = 203;
+ private static final int KEY_RING_SECRET = 204;
+ private static final int KEY_RING_CERTS = 205;
private static final int API_APPS = 301;
- private static final int API_APPS_BY_ROW_ID = 302;
private static final int API_APPS_BY_PACKAGE_NAME = 303;
+ private static final int API_ACCOUNTS = 304;
+ private static final int API_ACCOUNTS_BY_ACCOUNT_NAME = 306;
- private static final int UNIFIED_KEY_RING = 401;
+ private static final int KEY_RINGS_FIND_BY_EMAIL = 400;
+ private static final int KEY_RINGS_FIND_BY_SUBKEY = 401;
- private static final int CERTS = 401;
- private static final int CERTS_BY_KEY_ID = 402;
- private static final int CERTS_BY_ROW_ID = 403;
- private static final int CERTS_BY_KEY_ROW_ID = 404;
- private static final int CERTS_BY_KEY_ROW_ID_ALL = 405;
- private static final int CERTS_BY_CERTIFIER_ID = 406;
- private static final int CERTS_BY_KEY_ROW_ID_HAS_SECRET = 407;
+ private static final int CERTS_FIND_BY_CERTIFIER_ID = 501;
- // private static final int DATA_STREAM = 401;
+ // private static final int DATA_STREAM = 501;
protected UriMatcher mUriMatcher;
@@ -98,171 +79,85 @@ public class KeychainProvider extends ContentProvider {
String authority = KeychainContract.CONTENT_AUTHORITY;
/**
- * unified key rings
- *
- * <pre>
- * key_rings
- * </pre>
- */
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS, UNIFIED_KEY_RING);
-
- /**
- * public key rings
+ * list key_rings
*
* <pre>
+ * key_rings/unified
* key_rings/public
- * key_rings/public/#
- * key_rings/public/master_key_id/_
- * key_rings/public/key_id/_
- * key_rings/public/emails/_
- * key_rings/public/like_email/_
* </pre>
*/
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC, PUBLIC_KEY_RING);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC + "/#", PUBLIC_KEY_RING_BY_ROW_ID);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_MASTER_KEY_ID
- + "/*", PUBLIC_KEY_RING_BY_MASTER_KEY_ID);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_KEY_ID + "/*",
- PUBLIC_KEY_RING_BY_KEY_ID);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_EMAILS + "/*",
- PUBLIC_KEY_RING_BY_EMAILS);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_EMAILS,
- PUBLIC_KEY_RING_BY_EMAILS); // without emails specified
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_LIKE_EMAIL + "/*",
- PUBLIC_KEY_RING_BY_LIKE_EMAIL);
+ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS
+ + "/" + KeychainContract.PATH_UNIFIED,
+ KEY_RINGS_UNIFIED);
+ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS
+ + "/" + KeychainContract.PATH_PUBLIC,
+ KEY_RINGS_PUBLIC);
+ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS
+ + "/" + KeychainContract.PATH_SECRET,
+ KEY_RINGS_SECRET);
/**
- * public keys
+ * find by criteria other than master key id
*
- * <pre>
- * key_rings/public/#/keys
- * key_rings/public/#/keys/#
- * </pre>
- */
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC + "/#/" + KeychainContract.PATH_KEYS,
- PUBLIC_KEY_RING_KEY);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC + "/#/" + KeychainContract.PATH_KEYS + "/#",
- PUBLIC_KEY_RING_KEY_BY_ROW_ID);
-
- /**
- * public user ids
+ * key_rings/find/email/_
+ * key_rings/find/subkey/_
*
- * <pre>
- * key_rings/public/#/user_ids
- * key_rings/public/#/user_ids/#
- * key_rings/public/master_key_id/#/user_ids
- * </pre>
*/
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC + "/#/" + KeychainContract.PATH_USER_IDS,
- PUBLIC_KEY_RING_USER_ID);
+ + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_EMAIL + "/*",
+ KEY_RINGS_FIND_BY_EMAIL);
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC + "/#/" + KeychainContract.PATH_USER_IDS + "/#",
- PUBLIC_KEY_RING_USER_ID_BY_ROW_ID);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_PUBLIC + "/"
- + KeychainContract.PATH_BY_MASTER_KEY_ID + "/*/" + KeychainContract.PATH_USER_IDS,
- PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID);
+ + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_SUBKEY + "/*",
+ KEY_RINGS_FIND_BY_SUBKEY);
/**
- * secret key rings
+ * list key_ring specifics
*
* <pre>
- * key_rings/secret
- * key_rings/secret/#
- * key_rings/secret/master_key_id/_
- * key_rings/secret/key_id/_
- * key_rings/secret/emails/_
- * key_rings/secret/like_email/_
+ * key_rings/_/unified
+ * key_rings/_/keys
+ * key_rings/_/user_ids
+ * key_rings/_/public
+ * key_rings/_/secret
* </pre>
*/
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_SECRET, SECRET_KEY_RING);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_SECRET + "/#", SECRET_KEY_RING_BY_ROW_ID);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_MASTER_KEY_ID
- + "/*", SECRET_KEY_RING_BY_MASTER_KEY_ID);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_KEY_ID + "/*",
- SECRET_KEY_RING_BY_KEY_ID);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_EMAILS + "/*",
- SECRET_KEY_RING_BY_EMAILS);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_EMAILS,
- SECRET_KEY_RING_BY_EMAILS); // without emails specified
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_LIKE_EMAIL + "/*",
- SECRET_KEY_RING_BY_LIKE_EMAIL);
+ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
+ + KeychainContract.PATH_UNIFIED,
+ KEY_RING_UNIFIED);
+ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
+ + KeychainContract.PATH_KEYS,
+ KEY_RING_KEYS);
+ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
+ + KeychainContract.PATH_USER_IDS,
+ KEY_RING_USER_IDS);
+ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
+ + KeychainContract.PATH_PUBLIC,
+ KEY_RING_PUBLIC);
+ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
+ + KeychainContract.PATH_SECRET,
+ KEY_RING_SECRET);
+ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
+ + KeychainContract.PATH_CERTS,
+ KEY_RING_CERTS);
/**
- * secret keys
+ * API apps
*
* <pre>
- * key_rings/secret/#/keys
- * key_rings/secret/#/keys/#
- * </pre>
- */
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_SECRET + "/#/" + KeychainContract.PATH_KEYS,
- SECRET_KEY_RING_KEY);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_SECRET + "/#/" + KeychainContract.PATH_KEYS + "/#",
- SECRET_KEY_RING_KEY_BY_ROW_ID);
-
- /**
- * secret user ids
+ * api_apps
+ * api_apps/_ (package name)
*
- * <pre>
- * key_rings/secret/#/user_ids
- * key_rings/secret/#/user_ids/#
+ * api_apps/_/accounts
+ * api_apps/_/accounts/_ (account name)
* </pre>
*/
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_SECRET + "/#/" + KeychainContract.PATH_USER_IDS,
- SECRET_KEY_RING_USER_ID);
- matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
- + KeychainContract.PATH_SECRET + "/#/" + KeychainContract.PATH_USER_IDS + "/#",
- SECRET_KEY_RING_USER_ID_BY_ROW_ID);
-
- /**
- * API apps
- */
matcher.addURI(authority, KeychainContract.BASE_API_APPS, API_APPS);
- matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/#", API_APPS_BY_ROW_ID);
- matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/"
- + KeychainContract.PATH_BY_PACKAGE_NAME + "/*", API_APPS_BY_PACKAGE_NAME);
+ matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*", API_APPS_BY_PACKAGE_NAME);
- /**
- /**
- * certifications
- *
- * <pre>
- * </pre>
- *
- */
- matcher.addURI(authority, KeychainContract.BASE_CERTS, CERTS);
- matcher.addURI(authority, KeychainContract.BASE_CERTS + "/#", CERTS_BY_ROW_ID);
- matcher.addURI(authority, KeychainContract.BASE_CERTS + "/"
- + KeychainContract.PATH_BY_KEY_ROW_ID + "/#", CERTS_BY_KEY_ROW_ID);
- matcher.addURI(authority, KeychainContract.BASE_CERTS + "/"
- + KeychainContract.PATH_BY_KEY_ROW_ID + "/#/all", CERTS_BY_KEY_ROW_ID_ALL);
- matcher.addURI(authority, KeychainContract.BASE_CERTS + "/"
- + KeychainContract.PATH_BY_KEY_ROW_ID + "/#/has_secret", CERTS_BY_KEY_ROW_ID_HAS_SECRET);
- matcher.addURI(authority, KeychainContract.BASE_CERTS + "/"
- + KeychainContract.PATH_BY_KEY_ID + "/#", CERTS_BY_KEY_ID);
- matcher.addURI(authority, KeychainContract.BASE_CERTS + "/"
- + KeychainContract.PATH_BY_CERTIFIER_ID + "/#", CERTS_BY_CERTIFIER_ID);
+ matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/"
+ + KeychainContract.PATH_ACCOUNTS, API_ACCOUNTS);
+ matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/"
+ + KeychainContract.PATH_ACCOUNTS + "/*", API_ACCOUNTS_BY_ACCOUNT_NAME);
/**
* data stream
@@ -276,7 +171,7 @@ public class KeychainProvider extends ContentProvider {
return matcher;
}
- private KeychainDatabase mApgDatabase;
+ private KeychainDatabase mKeychainDatabase;
/**
* {@inheritDoc}
@@ -284,10 +179,15 @@ public class KeychainProvider extends ContentProvider {
@Override
public boolean onCreate() {
mUriMatcher = buildUriMatcher();
- mApgDatabase = new KeychainDatabase(getContext());
return true;
}
+ public KeychainDatabase getDb() {
+ if(mKeychainDatabase == null)
+ mKeychainDatabase = new KeychainDatabase(getContext());
+ return mKeychainDatabase;
+ }
+
/**
* {@inheritDoc}
*/
@@ -295,247 +195,44 @@ public class KeychainProvider extends ContentProvider {
public String getType(Uri uri) {
final int match = mUriMatcher.match(uri);
switch (match) {
- case PUBLIC_KEY_RING:
- case PUBLIC_KEY_RING_BY_EMAILS:
- case PUBLIC_KEY_RING_BY_LIKE_EMAIL:
- case SECRET_KEY_RING:
- case SECRET_KEY_RING_BY_EMAILS:
- case SECRET_KEY_RING_BY_LIKE_EMAIL:
- return KeyRings.CONTENT_TYPE;
-
- case PUBLIC_KEY_RING_BY_ROW_ID:
- case PUBLIC_KEY_RING_BY_MASTER_KEY_ID:
- case PUBLIC_KEY_RING_BY_KEY_ID:
- case SECRET_KEY_RING_BY_ROW_ID:
- case SECRET_KEY_RING_BY_MASTER_KEY_ID:
- case SECRET_KEY_RING_BY_KEY_ID:
+ case KEY_RING_PUBLIC:
return KeyRings.CONTENT_ITEM_TYPE;
- case PUBLIC_KEY_RING_KEY:
- case SECRET_KEY_RING_KEY:
+ case KEY_RING_KEYS:
return Keys.CONTENT_TYPE;
- case PUBLIC_KEY_RING_KEY_BY_ROW_ID:
- case SECRET_KEY_RING_KEY_BY_ROW_ID:
- return Keys.CONTENT_ITEM_TYPE;
-
- case PUBLIC_KEY_RING_USER_ID:
- case PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID:
- case SECRET_KEY_RING_USER_ID:
+ case KEY_RING_USER_IDS:
return UserIds.CONTENT_TYPE;
- case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID:
- case SECRET_KEY_RING_USER_ID_BY_ROW_ID:
- return UserIds.CONTENT_ITEM_TYPE;
+ case KEY_RING_SECRET:
+ return KeyRings.CONTENT_ITEM_TYPE;
case API_APPS:
return ApiApps.CONTENT_TYPE;
- case API_APPS_BY_ROW_ID:
case API_APPS_BY_PACKAGE_NAME:
return ApiApps.CONTENT_ITEM_TYPE;
- default:
- throw new UnsupportedOperationException("Unknown uri: " + uri);
- }
- }
+ case API_ACCOUNTS:
+ return ApiAccounts.CONTENT_TYPE;
- /**
- * Returns type of the query (secret/public)
- *
- * @param match
- * @return
- */
- private int getKeyType(int match) {
- int type;
- switch (match) {
- case PUBLIC_KEY_RING:
- case PUBLIC_KEY_RING_BY_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_BY_LIKE_EMAIL:
- case PUBLIC_KEY_RING_KEY:
- case PUBLIC_KEY_RING_KEY_BY_ROW_ID:
- case PUBLIC_KEY_RING_USER_ID:
- case PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID:
- case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID:
- type = KeyTypes.PUBLIC;
- break;
-
- case SECRET_KEY_RING:
- case SECRET_KEY_RING_BY_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_BY_LIKE_EMAIL:
- case SECRET_KEY_RING_KEY:
- case SECRET_KEY_RING_KEY_BY_ROW_ID:
- case SECRET_KEY_RING_USER_ID:
- case SECRET_KEY_RING_USER_ID_BY_ROW_ID:
- type = KeyTypes.SECRET;
- break;
+ case API_ACCOUNTS_BY_ACCOUNT_NAME:
+ return ApiAccounts.CONTENT_ITEM_TYPE;
default:
- Log.e(Constants.TAG, "Unknown match " + match);
- type = -1;
- break;
- }
-
- return type;
- }
-
- /**
- * Set result of query to specific columns, don't show blob column
- *
- * @return
- */
- private HashMap<String, String> getProjectionMapForKeyRings() {
- HashMap<String, String> projectionMap = new HashMap<String, String>();
-
- projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID);
- projectionMap.put(KeyRingsColumns.KEY_RING_DATA, Tables.KEY_RINGS + "."
- + KeyRingsColumns.KEY_RING_DATA);
- projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "."
- + KeyRingsColumns.MASTER_KEY_ID);
- // TODO: deprecated master key id
- //projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.KEY_ID);
-
- projectionMap.put(KeysColumns.ALGORITHM, Tables.KEYS + "." + KeysColumns.ALGORITHM);
- projectionMap.put(KeysColumns.KEY_SIZE, Tables.KEYS + "." + KeysColumns.KEY_SIZE);
- projectionMap.put(KeysColumns.CREATION, Tables.KEYS + "." + KeysColumns.CREATION);
- projectionMap.put(KeysColumns.EXPIRY, Tables.KEYS + "." + KeysColumns.EXPIRY);
- projectionMap.put(KeysColumns.KEY_RING_ROW_ID, Tables.KEYS + "." + KeysColumns.KEY_RING_ROW_ID);
- projectionMap.put(KeysColumns.FINGERPRINT, Tables.KEYS + "." + KeysColumns.FINGERPRINT);
- projectionMap.put(KeysColumns.IS_REVOKED, Tables.KEYS + "." + KeysColumns.IS_REVOKED);
-
- projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + UserIdsColumns.USER_ID);
-
- // type attribute is special: if there is any grouping, choose secret over public type
- projectionMap.put(KeyRingsColumns.TYPE,
- "MAX(" + Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + ") AS " + KeyRingsColumns.TYPE);
-
- return projectionMap;
- }
-
- /**
- * Set result of query to specific columns, don't show blob column
- *
- * @return
- */
- private HashMap<String, String> getProjectionMapForKeys() {
- HashMap<String, String> projectionMap = new HashMap<String, String>();
-
- projectionMap.put(BaseColumns._ID, BaseColumns._ID);
- projectionMap.put(KeysColumns.KEY_ID, KeysColumns.KEY_ID);
- projectionMap.put(KeysColumns.IS_MASTER_KEY, KeysColumns.IS_MASTER_KEY);
- projectionMap.put(KeysColumns.ALGORITHM, KeysColumns.ALGORITHM);
- projectionMap.put(KeysColumns.KEY_SIZE, KeysColumns.KEY_SIZE);
- projectionMap.put(KeysColumns.CAN_CERTIFY, KeysColumns.CAN_CERTIFY);
- projectionMap.put(KeysColumns.CAN_SIGN, KeysColumns.CAN_SIGN);
- projectionMap.put(KeysColumns.CAN_ENCRYPT, KeysColumns.CAN_ENCRYPT);
- projectionMap.put(KeysColumns.IS_REVOKED, KeysColumns.IS_REVOKED);
- projectionMap.put(KeysColumns.CREATION, KeysColumns.CREATION);
- projectionMap.put(KeysColumns.EXPIRY, KeysColumns.EXPIRY);
- projectionMap.put(KeysColumns.KEY_RING_ROW_ID, KeysColumns.KEY_RING_ROW_ID);
- projectionMap.put(KeysColumns.KEY_DATA, KeysColumns.KEY_DATA);
- projectionMap.put(KeysColumns.RANK, KeysColumns.RANK);
- projectionMap.put(KeysColumns.FINGERPRINT, KeysColumns.FINGERPRINT);
-
- return projectionMap;
- }
-
- private HashMap<String, String> getProjectionMapForUserIds() {
- HashMap<String, String> projectionMap = new HashMap<String, String>();
-
- projectionMap.put(BaseColumns._ID, Tables.USER_IDS + "." + BaseColumns._ID);
- projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + UserIdsColumns.USER_ID);
- projectionMap.put(UserIdsColumns.RANK, Tables.USER_IDS + "." + UserIdsColumns.RANK);
- projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "."
- + KeyRingsColumns.MASTER_KEY_ID);
-
- // this is the count of known secret keys who certified this uid
- projectionMap.put("verified", "COUNT(" + Tables.KEYS + "." + Keys._ID + ") AS verified");
-
- return projectionMap;
- }
- private HashMap<String, String> getProjectionMapForCerts() {
-
- HashMap<String, String> pmap = new HashMap<String, String>();
- pmap.put(Certs._ID, Tables.CERTS + "." + Certs._ID);
- pmap.put(Certs.KEY_ID, Tables.CERTS + "." + Certs.KEY_ID);
- pmap.put(Certs.RANK, Tables.CERTS + "." + Certs.RANK);
- pmap.put(Certs.CREATION, Tables.CERTS + "." + Certs.CREATION);
- pmap.put(Certs.KEY_ID_CERTIFIER, Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER);
- pmap.put(Certs.KEY_DATA, Tables.CERTS + "." + Certs.KEY_DATA);
- pmap.put(Certs.VERIFIED, Tables.CERTS + "." + Certs.VERIFIED);
- // verified key data
- pmap.put(UserIds.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID);
- // verifying key data
- pmap.put("signer_uid", "signer." + UserIds.USER_ID + " AS signer_uid");
-
- return pmap;
- }
-
- /**
- * Builds default query for keyRings: KeyRings table is joined with UserIds and Keys
- */
- private SQLiteQueryBuilder buildKeyRingQuery(SQLiteQueryBuilder qb, int match) {
- if (match != UNIFIED_KEY_RING) {
- // public or secret keyring
- qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = ");
- qb.appendWhereEscapeString(Integer.toString(getKeyType(match)));
+ throw new UnsupportedOperationException("Unknown uri: " + uri);
}
-
- // join keyrings with keys and userIds
- // Only get user id and key with rank 0 (main user id and main key)
- 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.RANK + " = '0') " + " INNER JOIN " + Tables.USER_IDS + " ON "
- + "(" + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.USER_IDS + "."
- + UserIdsColumns.KEY_RING_ROW_ID + " AND " + Tables.USER_IDS + "."
- + UserIdsColumns.RANK + " = '0')");
-
- qb.setProjectionMap(getProjectionMapForKeyRings());
-
- return qb;
- }
-
- /**
- * Builds default query for keyRings: KeyRings table is joined with UserIds and Keys
- * <p/>
- * Here only one key should be selected in the query to return a single keyring!
- */
- private SQLiteQueryBuilder buildKeyRingQueryWithSpecificKey(SQLiteQueryBuilder qb, int match) {
- // public or secret keyring
- qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = ");
- qb.appendWhereEscapeString(Integer.toString(getKeyType(match)));
-
- // join keyrings with keys and userIds to every keyring
- qb.setTables(Tables.KEY_RINGS + " INNER JOIN " + Tables.KEYS + " ON " + "("
- + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.KEYS + "."
- + KeysColumns.KEY_RING_ROW_ID + ") " + " INNER JOIN " + Tables.USER_IDS + " ON "
- + "(" + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.USER_IDS + "."
- + UserIdsColumns.KEY_RING_ROW_ID + " AND " + Tables.USER_IDS + "."
- + UserIdsColumns.RANK + " = '0')");
-
- qb.setProjectionMap(getProjectionMapForKeyRings());
-
- return qb;
}
/**
* {@inheritDoc}
*/
- @SuppressWarnings("deprecation")
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
Log.v(Constants.TAG, "query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")");
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- SQLiteDatabase db = mApgDatabase.getReadableDatabase();
int match = mUriMatcher.match(uri);
@@ -543,227 +240,224 @@ public class KeychainProvider extends ContentProvider {
String groupBy = null, having = null;
switch (match) {
- case UNIFIED_KEY_RING:
- qb = buildKeyRingQuery(qb, match);
-
- // GROUP BY so we don't get duplicates
- groupBy = Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID;
-
- if (TextUtils.isEmpty(sortOrder)) {
- sortOrder = KeyRings.TYPE + " DESC, " +
- Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC";
+ case KEY_RING_UNIFIED:
+ case KEY_RINGS_UNIFIED:
+ case KEY_RINGS_FIND_BY_EMAIL:
+ case KEY_RINGS_FIND_BY_SUBKEY: {
+ HashMap<String, String> projectionMap = new HashMap<String, String>();
+ projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id");
+ projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
+ projectionMap.put(KeyRings.KEY_ID, Keys.KEY_ID);
+ projectionMap.put(KeyRings.KEY_SIZE, Keys.KEY_SIZE);
+ projectionMap.put(KeyRings.IS_REVOKED, Keys.IS_REVOKED);
+ projectionMap.put(KeyRings.CAN_CERTIFY, Keys.CAN_CERTIFY);
+ projectionMap.put(KeyRings.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
+ projectionMap.put(KeyRings.CAN_SIGN, Keys.CAN_SIGN);
+ projectionMap.put(KeyRings.CREATION, Keys.CREATION);
+ projectionMap.put(KeyRings.EXPIRY, Keys.EXPIRY);
+ projectionMap.put(KeyRings.ALGORITHM, Keys.ALGORITHM);
+ projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT);
+ projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID);
+ projectionMap.put(KeyRings.HAS_SECRET, "(" + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NOT NULL) AS " + KeyRings.HAS_SECRET);
+ qb.setProjectionMap(projectionMap);
+
+ qb.setTables(
+ Tables.KEYS
+ + " INNER JOIN " + Tables.USER_IDS + " ON ("
+ + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ + " = "
+ + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID
+ + " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = 0"
+ + ") LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON ("
+ + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ + " = "
+ + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID
+ + ")"
+ );
+ qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0");
+
+ switch(match) {
+ case KEY_RING_UNIFIED: {
+ qb.appendWhere(" AND " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = ");
+ qb.appendWhereEscapeString(uri.getPathSegments().get(1));
+ break;
+ }
+ case KEY_RINGS_FIND_BY_SUBKEY: {
+ try {
+ String subkey = Long.valueOf(uri.getLastPathSegment()).toString();
+ qb.appendWhere(" AND EXISTS ("
+ + " SELECT 1 FROM " + Tables.KEYS + " AS tmp"
+ + " WHERE tmp." + UserIds.MASTER_KEY_ID
+ + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ + " AND tmp." + Keys.KEY_ID + " = " + subkey + ""
+ + ")");
+ } catch(NumberFormatException e) {
+ Log.e(Constants.TAG, "Malformed find by subkey query!", e);
+ qb.appendWhere(" AND 0");
+ }
+ break;
+ }
+ case KEY_RINGS_FIND_BY_EMAIL: {
+ String chunks[] = uri.getLastPathSegment().split(" *, *");
+ boolean gotCondition = false;
+ String emailWhere = "";
+ // JAVA ♥
+ for (int i = 0; i < chunks.length; ++i) {
+ if (chunks[i].length() == 0) {
+ continue;
+ }
+ if (i != 0) {
+ emailWhere += " OR ";
+ }
+ emailWhere += "tmp." + UserIds.USER_ID + " LIKE ";
+ // match '*<email>', so it has to be at the *end* of the user id
+ emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">");
+ gotCondition = true;
+ }
+ if(gotCondition) {
+ qb.appendWhere(" AND EXISTS ("
+ + " SELECT 1 FROM " + Tables.USER_IDS + " AS tmp"
+ + " WHERE tmp." + UserIds.MASTER_KEY_ID
+ + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ + " AND (" + emailWhere + ")"
+ + ")");
+ } else {
+ // TODO better way to do this?
+ Log.e(Constants.TAG, "Malformed find by email query!");
+ qb.appendWhere(" AND 0");
+ }
+ break;
+ }
}
- break;
-
- case PUBLIC_KEY_RING:
- case SECRET_KEY_RING:
- qb = buildKeyRingQuery(qb, match);
-
if (TextUtils.isEmpty(sortOrder)) {
- sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC";
+ sortOrder =
+ Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL ASC, "
+ + Tables.USER_IDS + "." + UserIds.USER_ID + " ASC";
}
- break;
-
- case PUBLIC_KEY_RING_BY_ROW_ID:
- case SECRET_KEY_RING_BY_ROW_ID:
- qb = buildKeyRingQuery(qb, match);
-
- qb.appendWhere(" AND " + Tables.KEY_RINGS + "." + BaseColumns._ID + " = ");
- qb.appendWhereEscapeString(uri.getLastPathSegment());
-
- if (TextUtils.isEmpty(sortOrder)) {
- sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC";
- }
+ // uri to watch is all /key_rings/
+ uri = KeyRings.CONTENT_URI;
break;
+ }
- case PUBLIC_KEY_RING_BY_MASTER_KEY_ID:
- case SECRET_KEY_RING_BY_MASTER_KEY_ID:
- qb = buildKeyRingQuery(qb, match);
-
- qb.appendWhere(" AND " + Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID + " = ");
- qb.appendWhereEscapeString(uri.getLastPathSegment());
+ case KEY_RING_KEYS: {
+ HashMap<String, String> projectionMap = new HashMap<String, String>();
+ projectionMap.put(Keys._ID, Tables.KEYS + ".oid AS _id");
+ projectionMap.put(Keys.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
+ projectionMap.put(Keys.RANK, Tables.KEYS + "." + Keys.RANK);
+ projectionMap.put(Keys.KEY_ID, Keys.KEY_ID);
+ projectionMap.put(Keys.KEY_SIZE, Keys.KEY_SIZE);
+ projectionMap.put(Keys.IS_REVOKED, Keys.IS_REVOKED);
+ projectionMap.put(Keys.CAN_CERTIFY, Keys.CAN_CERTIFY);
+ projectionMap.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
+ projectionMap.put(Keys.CAN_SIGN, Keys.CAN_SIGN);
+ projectionMap.put(Keys.CREATION, Keys.CREATION);
+ projectionMap.put(Keys.EXPIRY, Keys.EXPIRY);
+ projectionMap.put(Keys.ALGORITHM, Keys.ALGORITHM);
+ projectionMap.put(Keys.FINGERPRINT, Keys.FINGERPRINT);
+ qb.setProjectionMap(projectionMap);
- if (TextUtils.isEmpty(sortOrder)) {
- sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC";
- }
+ qb.setTables(Tables.KEYS);
+ qb.appendWhere(Keys.MASTER_KEY_ID + " = ");
+ qb.appendWhereEscapeString(uri.getPathSegments().get(1));
break;
+ }
- case SECRET_KEY_RING_BY_KEY_ID:
- case PUBLIC_KEY_RING_BY_KEY_ID:
- qb = buildKeyRingQueryWithSpecificKey(qb, match);
+ case KEY_RING_USER_IDS: {
+ HashMap<String, String> projectionMap = new HashMap<String, String>();
+ projectionMap.put(UserIds._ID, Tables.USER_IDS + ".oid AS _id");
+ projectionMap.put(UserIds.MASTER_KEY_ID, UserIds.MASTER_KEY_ID);
+ projectionMap.put(UserIds.USER_ID, UserIds.USER_ID);
+ projectionMap.put(UserIds.RANK, UserIds.RANK);
+ projectionMap.put(UserIds.IS_PRIMARY, UserIds.IS_PRIMARY);
+ projectionMap.put(UserIds.VERIFIED, "0 AS " + UserIds.VERIFIED);
+ qb.setProjectionMap(projectionMap);
- qb.appendWhere(" AND " + Tables.KEYS + "." + KeysColumns.KEY_ID + " = ");
- qb.appendWhereEscapeString(uri.getLastPathSegment());
+ qb.setTables(Tables.USER_IDS);
+ qb.appendWhere(UserIds.MASTER_KEY_ID + " = ");
+ qb.appendWhereEscapeString(uri.getPathSegments().get(1));
if (TextUtils.isEmpty(sortOrder)) {
- sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC";
+ sortOrder = UserIds.RANK + " ASC";
}
break;
- case SECRET_KEY_RING_BY_EMAILS:
- case PUBLIC_KEY_RING_BY_EMAILS:
- qb = buildKeyRingQuery(qb, match);
-
- String emails = uri.getLastPathSegment();
- String chunks[] = emails.split(" *, *");
- boolean gotCondition = false;
- String emailWhere = "";
- for (int i = 0; i < chunks.length; ++i) {
- if (chunks[i].length() == 0) {
- continue;
- }
- if (i != 0) {
- emailWhere += " OR ";
- }
- emailWhere += "tmp." + UserIdsColumns.USER_ID + " LIKE ";
- // match '*<email>', so it has to be at the *end* of the user id
- emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">");
- gotCondition = true;
- }
-
- if (gotCondition) {
- qb.appendWhere(" AND EXISTS (SELECT tmp." + BaseColumns._ID + " FROM "
- + Tables.USER_IDS + " AS tmp WHERE tmp." + UserIdsColumns.KEY_RING_ROW_ID
- + " = " + Tables.KEY_RINGS + "." + BaseColumns._ID + " AND (" + emailWhere
- + "))");
- }
-
- break;
-
- case SECRET_KEY_RING_BY_LIKE_EMAIL:
- case PUBLIC_KEY_RING_BY_LIKE_EMAIL:
- qb = buildKeyRingQuery(qb, match);
-
- String likeEmail = uri.getLastPathSegment();
-
- String likeEmailWhere = "tmp." + UserIdsColumns.USER_ID + " LIKE "
- + DatabaseUtils.sqlEscapeString("%<%" + likeEmail + "%>");
-
- qb.appendWhere(" AND EXISTS (SELECT tmp." + BaseColumns._ID + " FROM "
- + Tables.USER_IDS + " AS tmp WHERE tmp." + UserIdsColumns.KEY_RING_ROW_ID
- + " = " + Tables.KEY_RINGS + "." + BaseColumns._ID + " AND (" + likeEmailWhere
- + "))");
-
- break;
+ }
- case PUBLIC_KEY_RING_KEY:
- case SECRET_KEY_RING_KEY:
- qb.setTables(Tables.KEYS);
- qb.appendWhere(KeysColumns.TYPE + " = ");
- qb.appendWhereEscapeString(Integer.toString(getKeyType(match)));
+ case KEY_RINGS_PUBLIC:
+ case KEY_RING_PUBLIC: {
+ HashMap<String, String> projectionMap = new HashMap<String, String>();
+ projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_PUBLIC + ".oid AS _id");
+ projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID);
+ projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA);
+ qb.setProjectionMap(projectionMap);
- qb.appendWhere(" AND " + KeysColumns.KEY_RING_ROW_ID + " = ");
- qb.appendWhereEscapeString(uri.getPathSegments().get(2));
+ qb.setTables(Tables.KEY_RINGS_PUBLIC);
- qb.setProjectionMap(getProjectionMapForKeys());
+ if(match == KEY_RING_PUBLIC) {
+ qb.appendWhere(KeyRings.MASTER_KEY_ID + " = ");
+ qb.appendWhereEscapeString(uri.getPathSegments().get(1));
+ }
break;
+ }
- case PUBLIC_KEY_RING_KEY_BY_ROW_ID:
- case SECRET_KEY_RING_KEY_BY_ROW_ID:
- qb.setTables(Tables.KEYS);
- qb.appendWhere(KeysColumns.TYPE + " = ");
- qb.appendWhereEscapeString(Integer.toString(getKeyType(match)));
-
- qb.appendWhere(" AND " + KeysColumns.KEY_RING_ROW_ID + " = ");
- qb.appendWhereEscapeString(uri.getPathSegments().get(2));
-
- qb.appendWhere(" AND " + BaseColumns._ID + " = ");
- qb.appendWhereEscapeString(uri.getLastPathSegment());
-
- qb.setProjectionMap(getProjectionMapForKeys());
+ case KEY_RINGS_SECRET:
+ case KEY_RING_SECRET: {
+ HashMap<String, String> projectionMap = new HashMap<String, String>();
+ projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_SECRET + ".oid AS _id");
+ projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID);
+ projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA);
+ qb.setProjectionMap(projectionMap);
- break;
+ qb.setTables(Tables.KEY_RINGS_SECRET);
- case PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID:
- case PUBLIC_KEY_RING_USER_ID:
- case SECRET_KEY_RING_USER_ID:
- qb.setTables(Tables.USER_IDS
- + " INNER JOIN " + Tables.KEY_RINGS + " ON ("
- + Tables.KEY_RINGS + "." + BaseColumns._ID + " = "
- + Tables.USER_IDS + "." + KeysColumns.KEY_RING_ROW_ID
- + ") LEFT JOIN " + Tables.CERTS + " ON ("
- + Tables.USER_IDS + "." + UserIds.KEY_RING_ROW_ID + " = "
- + Tables.CERTS + "." + Certs.KEY_RING_ROW_ID
- + " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = "
- + Tables.CERTS + "." + Certs.RANK
- + ") LEFT JOIN " + Tables.KEYS + " ON ("
- + Tables.KEYS + "." + Keys.KEY_ID + " = "
- + Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER
- // might introduce a "trusted" flag later? for now, we simply assume
- // every private key's signature is good.
- + " AND " + Tables.KEYS + "." + Keys.TYPE
- + " == " + KeyTypes.SECRET
- + ")");
-
- groupBy = Tables.USER_IDS + "." + UserIds.RANK;
-
- qb.setProjectionMap(getProjectionMapForUserIds());
-
- if(match == PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID) {
- qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID + " = ");
- qb.appendWhereEscapeString(uri.getPathSegments().get(3));
- } else {
- qb.appendWhere(Tables.USER_IDS + "." + UserIdsColumns.KEY_RING_ROW_ID + " = ");
- qb.appendWhereEscapeString(uri.getPathSegments().get(2));
+ if(match == KEY_RING_SECRET) {
+ qb.appendWhere(KeyRings.MASTER_KEY_ID + " = ");
+ qb.appendWhereEscapeString(uri.getPathSegments().get(1));
}
break;
+ }
- case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID:
- case SECRET_KEY_RING_USER_ID_BY_ROW_ID:
- qb.setTables(Tables.USER_IDS);
- qb.appendWhere(UserIdsColumns.KEY_RING_ROW_ID + " = ");
- qb.appendWhereEscapeString(uri.getPathSegments().get(2));
-
- qb.appendWhere(" AND " + BaseColumns._ID + " = ");
- qb.appendWhereEscapeString(uri.getLastPathSegment());
-
- break;
+ case KEY_RING_CERTS:
+ HashMap<String, String> projectionMap = new HashMap<String, String>();
+ projectionMap.put(Certs._ID, Tables.CERTS + ".oid AS " + Certs._ID);
+ projectionMap.put(Certs.MASTER_KEY_ID, Tables.CERTS + "." + Certs.MASTER_KEY_ID);
+ projectionMap.put(Certs.RANK, Tables.CERTS + "." + Certs.RANK);
+ projectionMap.put(Certs.CREATION, Tables.CERTS + "." + Certs.CREATION);
+ projectionMap.put(Certs.KEY_ID_CERTIFIER, Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER);
+ projectionMap.put(Certs.VERIFIED, Tables.CERTS + "." + Certs.VERIFIED);
+ projectionMap.put(Certs.KEY_DATA, Tables.CERTS + "." + Certs.KEY_DATA);
+ // verified key data
+ projectionMap.put(Certs.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID);
+ // verifying key data
+ projectionMap.put(Certs.SIGNER_UID, "signer." + UserIds.USER_ID + " AS " + Certs.SIGNER_UID);
+ qb.setProjectionMap(projectionMap);
- case CERTS_BY_ROW_ID:
- case CERTS_BY_KEY_ROW_ID_ALL:
- case CERTS_BY_KEY_ROW_ID_HAS_SECRET:
- case CERTS_BY_KEY_ROW_ID:
qb.setTables(Tables.CERTS
+ " JOIN " + Tables.USER_IDS + " ON ("
- + Tables.CERTS + "." + Certs.KEY_RING_ROW_ID + " = "
- + Tables.USER_IDS + "." + UserIds.KEY_RING_ROW_ID
+ + Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = "
+ + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID
+ " AND "
+ Tables.CERTS + "." + Certs.RANK + " = "
+ Tables.USER_IDS + "." + UserIds.RANK
- // noooooooot sure about this~ database design
- + ")" + (match == CERTS_BY_KEY_ROW_ID_ALL ? " LEFT" : "")
- + " JOIN " + Tables.KEYS + " ON ("
- + Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER + " = "
- + Tables.KEYS + "." + Keys.KEY_ID
- + (match == CERTS_BY_KEY_ROW_ID_HAS_SECRET ?
- " AND " + Tables.KEYS + "." + Keys.TYPE + " = " + KeyTypes.SECRET : ""
- )
+ ") LEFT JOIN " + Tables.USER_IDS + " AS signer ON ("
- + Tables.KEYS + "." + Keys.KEY_RING_ROW_ID + " = "
- + "signer." + UserIds.KEY_RING_ROW_ID
+ + Tables.CERTS + "." + Keys.MASTER_KEY_ID + " = "
+ + "signer." + UserIds.MASTER_KEY_ID
+ " AND "
+ "signer." + Keys.RANK + " = 0"
+ ")");
- qb.setProjectionMap(getProjectionMapForCerts());
-
groupBy = Tables.CERTS + "." + Certs.RANK + ", "
+ Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER;
- if(match == CERTS_BY_ROW_ID) {
- qb.appendWhere(Tables.CERTS + "." + Certs._ID + " = ");
- qb.appendWhereEscapeString(uri.getPathSegments().get(1));
- } else {
- qb.appendWhere(Tables.CERTS + "." + Certs.KEY_RING_ROW_ID + " = ");
- qb.appendWhereEscapeString(uri.getPathSegments().get(2));
- }
+ qb.appendWhere(Tables.CERTS + "." + KeyRings.MASTER_KEY_ID + " = ");
+ qb.appendWhereEscapeString(uri.getPathSegments().get(1));
break;
@@ -771,22 +465,29 @@ public class KeychainProvider extends ContentProvider {
qb.setTables(Tables.API_APPS);
break;
- case API_APPS_BY_ROW_ID:
+ case API_APPS_BY_PACKAGE_NAME:
qb.setTables(Tables.API_APPS);
-
- qb.appendWhere(BaseColumns._ID + " = ");
+ qb.appendWhere(ApiApps.PACKAGE_NAME + " = ");
qb.appendWhereEscapeString(uri.getLastPathSegment());
break;
- case API_APPS_BY_PACKAGE_NAME:
- qb.setTables(Tables.API_APPS);
- qb.appendWhere(ApiApps.PACKAGE_NAME + " = ");
- qb.appendWhereEscapeString(uri.getPathSegments().get(2));
+ case API_ACCOUNTS:
+ qb.setTables(Tables.API_ACCOUNTS);
+ qb.appendWhere(Tables.API_ACCOUNTS + "." + ApiAccounts.PACKAGE_NAME + " = ");
+ qb.appendWhereEscapeString(uri.getPathSegments().get(1));
break;
+ case API_ACCOUNTS_BY_ACCOUNT_NAME:
+ qb.setTables(Tables.API_ACCOUNTS);
+ qb.appendWhere(Tables.API_ACCOUNTS + "." + ApiAccounts.PACKAGE_NAME + " = ");
+ qb.appendWhereEscapeString(uri.getPathSegments().get(1));
+
+ qb.appendWhere(" AND " + Tables.API_ACCOUNTS + "." + ApiAccounts.ACCOUNT_NAME + " = ");
+ qb.appendWhereEscapeString(uri.getLastPathSegment());
+ break;
default:
- throw new IllegalArgumentException("Unknown URI " + uri);
+ throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")");
}
@@ -798,6 +499,7 @@ public class KeychainProvider extends ContentProvider {
orderBy = sortOrder;
}
+ SQLiteDatabase db = getDb().getReadableDatabase();
Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, having, orderBy);
// Tell the cursor what uri to watch, so it knows when its source data changes
@@ -821,78 +523,72 @@ public class KeychainProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
Log.d(Constants.TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")");
- final SQLiteDatabase db = mApgDatabase.getWritableDatabase();
+ final SQLiteDatabase db = getDb().getWritableDatabase();
Uri rowUri = null;
- long rowId = -1;
+ Long keyId = null;
try {
final int match = mUriMatcher.match(uri);
switch (match) {
- case PUBLIC_KEY_RING:
- values.put(KeyRings.TYPE, KeyTypes.PUBLIC);
-
- rowId = db.insertOrThrow(Tables.KEY_RINGS, null, values);
- rowUri = KeyRings.buildPublicKeyRingsUri(Long.toString(rowId));
- sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
-
+ case KEY_RING_PUBLIC:
+ db.insertOrThrow(Tables.KEY_RINGS_PUBLIC, null, values);
+ keyId = values.getAsLong(KeyRings.MASTER_KEY_ID);
break;
- case PUBLIC_KEY_RING_KEY:
- values.put(Keys.TYPE, KeyTypes.PUBLIC);
- rowId = db.insertOrThrow(Tables.KEYS, null, values);
- rowUri = Keys.buildPublicKeysUri(Long.toString(rowId));
- sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
+ case KEY_RING_SECRET:
+ db.insertOrThrow(Tables.KEY_RINGS_SECRET, null, values);
+ keyId = values.getAsLong(KeyRings.MASTER_KEY_ID);
+ break;
+ case KEY_RING_KEYS:
+ Log.d(Constants.TAG, "keys");
+ db.insertOrThrow(Tables.KEYS, null, values);
+ keyId = values.getAsLong(Keys.MASTER_KEY_ID);
break;
- case PUBLIC_KEY_RING_USER_ID:
- rowId = db.insertOrThrow(Tables.USER_IDS, null, values);
- rowUri = UserIds.buildPublicUserIdsUri(Long.toString(rowId));
- sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
+ case KEY_RING_USER_IDS:
+ db.insertOrThrow(Tables.USER_IDS, null, values);
+ keyId = values.getAsLong(UserIds.MASTER_KEY_ID);
break;
- case SECRET_KEY_RING:
- values.put(KeyRings.TYPE, KeyTypes.SECRET);
- rowId = db.insertOrThrow(Tables.KEY_RINGS, null, values);
- rowUri = KeyRings.buildSecretKeyRingsUri(Long.toString(rowId));
- sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
+ case KEY_RING_CERTS:
+ db.insertOrThrow(Tables.CERTS, null, values);
+ keyId = values.getAsLong(Certs.MASTER_KEY_ID);
+ break;
+ case API_APPS:
+ db.insertOrThrow(Tables.API_APPS, null, values);
break;
- case SECRET_KEY_RING_KEY:
- values.put(Keys.TYPE, KeyTypes.SECRET);
- rowId = db.insertOrThrow(Tables.KEYS, null, values);
- rowUri = Keys.buildSecretKeysUri(Long.toString(rowId));
- sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
+ case API_ACCOUNTS:
+ // set foreign key automatically based on given uri
+ // e.g., api_apps/com.example.app/accounts/
+ String packageName = uri.getPathSegments().get(1);
+ values.put(ApiAccounts.PACKAGE_NAME, packageName);
- break;
- case SECRET_KEY_RING_USER_ID:
- rowId = db.insertOrThrow(Tables.USER_IDS, null, values);
- rowUri = UserIds.buildSecretUserIdsUri(Long.toString(rowId));
+ Log.d(Constants.TAG, "provider packageName: " + packageName);
- break;
- case API_APPS:
- rowId = db.insertOrThrow(Tables.API_APPS, null, values);
- rowUri = ApiApps.buildIdUri(Long.toString(rowId));
+ db.insertOrThrow(Tables.API_ACCOUNTS, null, values);
+ // TODO: this is wrong:
+// rowUri = ApiAccounts.buildIdUri(Long.toString(rowId));
break;
- case CERTS_BY_KEY_ROW_ID:
- rowId = db.insertOrThrow(Tables.CERTS, null, values);
- // kinda useless.. should this be buildCertsByKeyRowIdUri?
- // rowUri = Certs.buildCertsUri(Long.toString(rowId));
- rowUri = uri;
- break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
+ if(keyId != null) {
+ uri = KeyRings.buildGenericKeyRingUri(keyId.toString());
+ rowUri = uri;
+ }
+
// notify of changes in db
getContext().getContentResolver().notifyChange(uri, null);
} catch (SQLiteConstraintException e) {
- Log.e(Constants.TAG, "Constraint exception on insert! Entry already existing?");
+ Log.e(Constants.TAG, "Constraint exception on insert! Entry already existing?", e);
}
return rowUri;
@@ -902,51 +598,43 @@ public class KeychainProvider extends ContentProvider {
* {@inheritDoc}
*/
@Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
+ public int delete(Uri uri, String additionalSelection, String[] selectionArgs) {
Log.v(Constants.TAG, "delete(uri=" + uri + ")");
- final SQLiteDatabase db = mApgDatabase.getWritableDatabase();
+ final SQLiteDatabase db = getDb().getWritableDatabase();
int count;
final int match = mUriMatcher.match(uri);
- String defaultSelection = null;
switch (match) {
- case PUBLIC_KEY_RING_BY_ROW_ID:
- case SECRET_KEY_RING_BY_ROW_ID:
- defaultSelection = BaseColumns._ID + "=" + uri.getLastPathSegment();
- // corresponding keys and userIds are deleted by ON DELETE CASCADE
- count = db.delete(Tables.KEY_RINGS,
- buildDefaultKeyRingsSelection(defaultSelection, getKeyType(match), selection),
- selectionArgs);
- sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
- break;
- case PUBLIC_KEY_RING_BY_MASTER_KEY_ID:
- case SECRET_KEY_RING_BY_MASTER_KEY_ID:
- defaultSelection = KeyRings.MASTER_KEY_ID + "=" + uri.getLastPathSegment();
+ case KEY_RING_PUBLIC: {
+ @SuppressWarnings("ConstantConditions") // ensured by uriMatcher above
+ String selection = KeyRings.MASTER_KEY_ID + " = " + uri.getPathSegments().get(1);
+ if (!TextUtils.isEmpty(additionalSelection)) {
+ selection += " AND (" + additionalSelection + ")";
+ }
// corresponding keys and userIds are deleted by ON DELETE CASCADE
- count = db.delete(Tables.KEY_RINGS,
- buildDefaultKeyRingsSelection(defaultSelection, getKeyType(match), selection),
- selectionArgs);
- sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
- break;
- case PUBLIC_KEY_RING_KEY_BY_ROW_ID:
- case SECRET_KEY_RING_KEY_BY_ROW_ID:
- count = db.delete(Tables.KEYS,
- buildDefaultKeysSelection(uri, getKeyType(match), selection), selectionArgs);
- sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
+ count = db.delete(Tables.KEY_RINGS_PUBLIC, selection, selectionArgs);
+ uri = KeyRings.buildGenericKeyRingUri(uri.getPathSegments().get(1));
break;
- case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID:
- case SECRET_KEY_RING_USER_ID_BY_ROW_ID:
- count = db.delete(Tables.KEYS, buildDefaultUserIdsSelection(uri, selection),
- selectionArgs);
+ }
+ case KEY_RING_SECRET: {
+ @SuppressWarnings("ConstantConditions") // ensured by uriMatcher above
+ String selection = KeyRings.MASTER_KEY_ID + " = " + uri.getPathSegments().get(1);
+ if (!TextUtils.isEmpty(additionalSelection)) {
+ selection += " AND (" + additionalSelection + ")";
+ }
+ count = db.delete(Tables.KEY_RINGS_SECRET, selection, selectionArgs);
+ uri = KeyRings.buildGenericKeyRingUri(uri.getPathSegments().get(1));
break;
- case API_APPS_BY_ROW_ID:
- count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, false, selection),
+ }
+
+ case API_APPS_BY_PACKAGE_NAME:
+ count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, additionalSelection),
selectionArgs);
break;
- case API_APPS_BY_PACKAGE_NAME:
- count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, true, selection),
+ case API_ACCOUNTS_BY_ACCOUNT_NAME:
+ count = db.delete(Tables.API_ACCOUNTS, buildDefaultApiAccountsSelection(uri, additionalSelection),
selectionArgs);
break;
default:
@@ -966,58 +654,20 @@ public class KeychainProvider extends ContentProvider {
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
Log.v(Constants.TAG, "update(uri=" + uri + ", values=" + values.toString() + ")");
- final SQLiteDatabase db = mApgDatabase.getWritableDatabase();
+ final SQLiteDatabase db = mKeychainDatabase.getWritableDatabase();
String defaultSelection = null;
int count = 0;
try {
final int match = mUriMatcher.match(uri);
switch (match) {
- case PUBLIC_KEY_RING_BY_ROW_ID:
- case SECRET_KEY_RING_BY_ROW_ID:
- defaultSelection = BaseColumns._ID + "=" + uri.getLastPathSegment();
-
- count = db.update(
- Tables.KEY_RINGS,
- values,
- buildDefaultKeyRingsSelection(defaultSelection, getKeyType(match),
- selection), selectionArgs);
- sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
-
- break;
- case PUBLIC_KEY_RING_BY_MASTER_KEY_ID:
- case SECRET_KEY_RING_BY_MASTER_KEY_ID:
- defaultSelection = KeyRings.MASTER_KEY_ID + "=" + uri.getLastPathSegment();
-
- count = db.update(
- Tables.KEY_RINGS,
- values,
- buildDefaultKeyRingsSelection(defaultSelection, getKeyType(match),
- selection), selectionArgs);
- sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
-
- break;
- case PUBLIC_KEY_RING_KEY_BY_ROW_ID:
- case SECRET_KEY_RING_KEY_BY_ROW_ID:
- count = db
- .update(Tables.KEYS, values,
- buildDefaultKeysSelection(uri, getKeyType(match), selection),
- selectionArgs);
- sendBroadcastDatabaseChange(getKeyType(match), getType(uri));
-
- break;
- case PUBLIC_KEY_RING_USER_ID_BY_ROW_ID:
- case SECRET_KEY_RING_USER_ID_BY_ROW_ID:
- count = db.update(Tables.USER_IDS, values,
- buildDefaultUserIdsSelection(uri, selection), selectionArgs);
- break;
- case API_APPS_BY_ROW_ID:
- count = db.update(Tables.API_APPS, values,
- buildDefaultApiAppsSelection(uri, false, selection), selectionArgs);
- break;
case API_APPS_BY_PACKAGE_NAME:
count = db.update(Tables.API_APPS, values,
- buildDefaultApiAppsSelection(uri, true, selection), selectionArgs);
+ buildDefaultApiAppsSelection(uri, selection), selectionArgs);
+ break;
+ case API_ACCOUNTS_BY_ACCOUNT_NAME:
+ count = db.update(Tables.API_ACCOUNTS, values,
+ buildDefaultApiAccountsSelection(uri, selection), selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
@@ -1034,125 +684,36 @@ public class KeychainProvider extends ContentProvider {
}
/**
- * Build default selection statement for KeyRings. If no extra selection is specified only build
- * where clause with rowId
- *
- * @param defaultSelection
- * @param keyType
- * @param selection
- * @return
- */
- private String buildDefaultKeyRingsSelection(String defaultSelection, Integer keyType,
- String selection) {
- String andType = "";
- if (keyType != null) {
- andType = " AND " + KeyRingsColumns.TYPE + "=" + keyType;
- }
-
- String andSelection = "";
- if (!TextUtils.isEmpty(selection)) {
- andSelection = " AND (" + selection + ")";
- }
-
- return defaultSelection + 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 " + 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
+ * Build default selection statement for API apps. 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;
+ private String buildDefaultApiAppsSelection(Uri uri, String selection) {
+ String packageName = DatabaseUtils.sqlEscapeString(uri.getLastPathSegment());
String andSelection = "";
if (!TextUtils.isEmpty(selection)) {
andSelection = " AND (" + selection + ")";
}
- return BaseColumns._ID + "=" + rowId + andForeignKeyRing + andSelection;
+ return ApiApps.PACKAGE_NAME + "=" + packageName + andSelection;
}
- /**
- * Build default selection statement for API apps. If no extra selection is specified only build
- * where clause with rowId
- *
- * @param uri
- * @param selection
- * @return
- */
- private String buildDefaultApiAppsSelection(Uri uri, boolean packageSelection, String selection) {
- String lastPathSegment = uri.getLastPathSegment();
+ private String buildDefaultApiAccountsSelection(Uri uri, String selection) {
+ String packageName = DatabaseUtils.sqlEscapeString(uri.getPathSegments().get(1));
+ String accountName = DatabaseUtils.sqlEscapeString(uri.getLastPathSegment());
String andSelection = "";
if (!TextUtils.isEmpty(selection)) {
andSelection = " AND (" + selection + ")";
}
- if (packageSelection) {
- return ApiApps.PACKAGE_NAME + "=" + lastPathSegment + andSelection;
- } else {
- return BaseColumns._ID + "=" + lastPathSegment + andSelection;
- }
+ return ApiAccounts.PACKAGE_NAME + "=" + packageName + " AND "
+ + ApiAccounts.ACCOUNT_NAME + "=" + accountName
+ + andSelection;
}
- // @Override
- // public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- // int match = mUriMatcher.match(uri);
- // if (match != DATA_STREAM) {
- // throw new FileNotFoundException();
- // }
- // String fileName = uri.getLastPathSegment();
- // File file = new File(getContext().getFilesDir().getAbsolutePath(), fileName);
- // return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
- // }
-
- /**
- * This broadcast is send system wide to inform other application that a keyring was inserted,
- * updated, or deleted
- */
- private void sendBroadcastDatabaseChange(int keyType, String contentItemType) {
- // TODO: Disabled, old API
- // Intent intent = new Intent();
- // intent.setAction(ACTION_BROADCAST_DATABASE_CHANGE);
- // intent.putExtra(EXTRA_BROADCAST_KEY_TYPE, keyType);
- // intent.putExtra(EXTRA_BROADCAST_CONTENT_ITEM_TYPE, contentItemType);
- //
- // getContext().sendBroadcast(intent, Constants.PERMISSION_ACCESS_API);
- }
}
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java
index da1bcb2d9..bc7de0b37 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java
@@ -25,7 +25,7 @@ import android.provider.BaseColumns;
import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.BlobsColumns;
public class KeychainServiceBlobDatabase extends SQLiteOpenHelper {
- private static final String DATABASE_NAME = "apg_blob.db";
+ private static final String DATABASE_NAME = "openkeychain_blob.db";
private static final int DATABASE_VERSION = 2;
public static final String TABLE = "data";
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java
index 6ac61e157..aa30e845d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java
@@ -38,7 +38,7 @@ import java.util.List;
import java.util.UUID;
public class KeychainServiceBlobProvider extends ContentProvider {
- private static final String STORE_PATH = Constants.Path.APP_DIR + "/ApgBlobs";
+ private static final String STORE_PATH = Constants.Path.APP_DIR + "/KeychainBlobs";
private KeychainServiceBlobDatabase mBlobDatabase = null;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index 1d249c67e..503fed3c9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -19,27 +19,36 @@ package org.sufficientlysecure.keychain.provider;
import java.security.SignatureException;
import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.bcpg.UserAttributePacket;
-import org.spongycastle.bcpg.UserAttributeSubpacket;
-import android.content.*;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.OperationApplicationException;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
import android.os.RemoteException;
-import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.spongycastle.openpgp.*;
+
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
+import org.spongycastle.openpgp.PGPKeyRing;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
+import org.spongycastle.openpgp.PGPSecretKeyRing;
+import org.spongycastle.openpgp.PGPSignature;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
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.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
-import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
-import org.sufficientlysecure.keychain.service.remote.AppSettings;
+import org.sufficientlysecure.keychain.remote.AccountSettings;
+import org.sufficientlysecure.keychain.remote.AppSettings;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
@@ -49,27 +58,82 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
-
+import java.util.HashSet;
+import java.util.Set;
public class ProviderHelper {
- /**
- * Private helper method to get PGPKeyRing from database
- */
+ // If we ever switch to api level 11, we can ditch this whole mess!
+ public static final int FIELD_TYPE_NULL = 1;
+ // this is called integer to stay coherent with the constants in Cursor (api level 11)
+ public static final int FIELD_TYPE_INTEGER = 2;
+ public static final int FIELD_TYPE_FLOAT = 3;
+ public static final int FIELD_TYPE_STRING = 4;
+ public static final int FIELD_TYPE_BLOB = 5;
+
+ public static Object getGenericData(Context context, Uri uri, String column, int type) {
+ return getGenericData(context, uri, new String[] { column }, new int[] { type }).get(column);
+ }
+ public static HashMap<String,Object> getGenericData(Context context, Uri uri, String[] proj, int[] types) {
+ Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
+
+ HashMap<String, Object> result = new HashMap<String, Object>(proj.length);
+ if (cursor != null && cursor.moveToFirst()) {
+ int pos = 0;
+ for(String p : proj) {
+ switch(types[pos]) {
+ case FIELD_TYPE_NULL: result.put(p, cursor.isNull(pos)); break;
+ case FIELD_TYPE_INTEGER: result.put(p, cursor.getLong(pos)); break;
+ case FIELD_TYPE_FLOAT: result.put(p, cursor.getFloat(pos)); break;
+ case FIELD_TYPE_STRING: result.put(p, cursor.getString(pos)); break;
+ case FIELD_TYPE_BLOB: result.put(p, cursor.getBlob(pos)); break;
+ }
+ pos += 1;
+ }
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return result;
+ }
+
+ public static Object getUnifiedData(Context context, long masterKeyId, String column, int type) {
+ return getUnifiedData(context, masterKeyId, new String[] { column }, new int[] { type }).get(column);
+ }
+ public static HashMap<String,Object> getUnifiedData(Context context, long masterKeyId, String[] proj, int[] types) {
+ return getGenericData(context, KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)), proj, types);
+ }
+
+ public static long getMasterKeyId(Context context, Uri queryUri) {
+ // try extracting from the uri first
+ String firstSegment = queryUri.getPathSegments().get(1);
+ if(!firstSegment.equals("find")) try {
+ return Long.parseLong(firstSegment);
+ } catch(NumberFormatException e) {
+ // didn't work? oh well.
+ Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying...");
+ }
+ Object data = getGenericData(context, queryUri, KeyRings.MASTER_KEY_ID, FIELD_TYPE_INTEGER);
+ if(data != null)
+ return (Long) data;
+ // TODO better error handling?
+ return 0L;
+ }
+
public static Map<Long, PGPKeyRing> getPGPKeyRings(Context context, Uri queryUri) {
Cursor cursor = context.getContentResolver().query(queryUri,
- new String[]{KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.KEY_RING_DATA}, null, null, null);
+ new String[]{KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA },
+ null, null, null);
Map<Long, PGPKeyRing> result = new HashMap<Long, PGPKeyRing>(cursor.getCount());
if (cursor != null && cursor.moveToFirst()) do {
- int keyRingDataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA);
- int masterKeyIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
-
- byte[] data = cursor.getBlob(keyRingDataCol);
+ long masterKeyId = cursor.getLong(0);
+ byte[] data = cursor.getBlob(1);
if (data != null) {
- result.put(cursor.getLong(masterKeyIdCol), PgpConversionHelper.BytesToPGPKeyRing(data));
+ result.put(masterKeyId, PgpConversionHelper.BytesToPGPKeyRing(data));
}
-
} while(cursor.moveToNext());
if (cursor != null) {
@@ -79,82 +143,46 @@ public class ProviderHelper {
return result;
}
public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) {
- return getPGPKeyRings(context, queryUri).values().iterator().next();
+ Map<Long, PGPKeyRing> result = getPGPKeyRings(context, queryUri);
+ if(result.isEmpty())
+ return null;
+ return result.values().iterator().next();
}
- /**
- * Retrieves the actual PGPPublicKeyRing object from the database blob based on the rowId
- */
- public static PGPPublicKeyRing getPGPPublicKeyRingByRowId(Context context, long rowId) {
- Uri queryUri = KeyRings.buildPublicKeyRingsUri(Long.toString(rowId));
- return (PGPPublicKeyRing) getPGPKeyRing(context, queryUri);
+ public static PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(Context context, long keyId) {
+ Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId));
+ long masterKeyId = getMasterKeyId(context, uri);
+ if(masterKeyId != 0)
+ return getPGPPublicKeyRing(context, masterKeyId);
+ return null;
+ }
+ public static PGPSecretKeyRing getPGPSecretKeyRingWithKeyId(Context context, long keyId) {
+ Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId));
+ long masterKeyId = getMasterKeyId(context, uri);
+ if(masterKeyId != 0)
+ return getPGPSecretKeyRing(context, masterKeyId);
+ return null;
}
/**
* Retrieves the actual PGPPublicKeyRing object from the database blob based on the masterKeyId
*/
- public static PGPPublicKeyRing getPGPPublicKeyRingByMasterKeyId(Context context,
+ public static PGPPublicKeyRing getPGPPublicKeyRing(Context context,
long masterKeyId) {
- Uri queryUri = KeyRings.buildPublicKeyRingsByMasterKeyIdUri(Long.toString(masterKeyId));
- return (PGPPublicKeyRing) getPGPKeyRing(context, queryUri);
- }
-
- /**
- * Retrieves the actual PGPPublicKeyRing object from the database blob associated with a key
- * with this keyId
- */
- public static PGPPublicKeyRing getPGPPublicKeyRingByKeyId(Context context, long keyId) {
- Uri queryUri = KeyRings.buildPublicKeyRingsByKeyIdUri(Long.toString(keyId));
+ Uri queryUri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId));
return (PGPPublicKeyRing) getPGPKeyRing(context, queryUri);
}
/**
- * Retrieves the actual PGPPublicKey object from the database blob associated with a key with
- * this keyId
- */
- public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long keyId) {
- PGPPublicKeyRing keyRing = getPGPPublicKeyRingByKeyId(context, keyId);
-
- return (keyRing == null) ? null : keyRing.getPublicKey(keyId);
- }
-
- /**
- * Retrieves the actual PGPSecretKeyRing object from the database blob based on the rowId
- */
- public static PGPSecretKeyRing getPGPSecretKeyRingByRowId(Context context, long rowId) {
- Uri queryUri = KeyRings.buildSecretKeyRingsUri(Long.toString(rowId));
- return (PGPSecretKeyRing) getPGPKeyRing(context, queryUri);
- }
-
- /**
* Retrieves the actual PGPSecretKeyRing object from the database blob based on the maserKeyId
*/
- public static PGPSecretKeyRing getPGPSecretKeyRingByMasterKeyId(Context context,
+ public static PGPSecretKeyRing getPGPSecretKeyRing(Context context,
long masterKeyId) {
- Uri queryUri = KeyRings.buildSecretKeyRingsByMasterKeyIdUri(Long.toString(masterKeyId));
+ Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
return (PGPSecretKeyRing) getPGPKeyRing(context, queryUri);
}
/**
- * Retrieves the actual PGPSecretKeyRing object from the database blob associated with a key
- * with this keyId
- */
- public static PGPSecretKeyRing getPGPSecretKeyRingByKeyId(Context context, long keyId) {
- Uri queryUri = KeyRings.buildSecretKeyRingsByKeyIdUri(Long.toString(keyId));
- return (PGPSecretKeyRing) getPGPKeyRing(context, queryUri);
- }
-
- /**
- * Retrieves the actual PGPSecretKey object from the database blob associated with a key with
- * this keyId
- */
- public static PGPSecretKey getPGPSecretKeyByKeyId(Context context, long keyId) {
- PGPSecretKeyRing keyRing = getPGPSecretKeyRingByKeyId(context, keyId);
-
- return (keyRing == null) ? null : keyRing.getSecretKey(keyId);
- }
-
- /**
* Saves PGPPublicKeyRing with its keys and userIds in DB
*/
@SuppressWarnings("unchecked")
@@ -162,21 +190,12 @@ public class ProviderHelper {
PGPPublicKey masterKey = keyRing.getPublicKey();
long masterKeyId = masterKey.getKeyID();
- Uri deleteUri = KeyRings.buildPublicKeyRingsByMasterKeyIdUri(Long.toString(masterKeyId));
-
- // get current _ID of key
- long currentRowId = -1;
- Cursor oldQuery = context.getContentResolver()
- .query(deleteUri, new String[]{KeyRings._ID}, null, null, null);
- if (oldQuery != null && oldQuery.moveToFirst()) {
- currentRowId = oldQuery.getLong(0);
- } else {
- Log.e(Constants.TAG, "Key could not be found! Something wrong is happening!");
- }
+ // IF there is a secret key, preserve it!
+ PGPSecretKeyRing secretRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId);
// delete old version of this keyRing, which also deletes all keys and userIds on cascade
try {
- context.getContentResolver().delete(deleteUri, null, null);
+ context.getContentResolver().delete(KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null);
} catch (UnsupportedOperationException e) {
Log.e(Constants.TAG, "Key could not be deleted! Maybe we are creating a new one!", e);
}
@@ -186,32 +205,28 @@ public class ProviderHelper {
// NOTE: If we would not use the same _ID again,
// getting back to the ViewKeyActivity would result in Nullpointer,
// because the currently loaded key would be gone from the database
- if (currentRowId != -1) {
- values.put(KeyRings._ID, currentRowId);
- }
- values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
- values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
+ values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
+ values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded());
// insert new version of this keyRing
- Uri uri = KeyRings.buildPublicKeyRingsUri();
+ Uri uri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId));
Uri insertedUri = context.getContentResolver().insert(uri, values);
- long keyRingRowId = Long.valueOf(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));
+ operations.add(buildPublicKeyOperations(context, masterKeyId, key, rank));
++rank;
}
// get a list of owned secret keys, for verification filtering
- Map<Long, PGPKeyRing> allKeyRings = getPGPKeyRings(context, KeyRings.buildSecretKeyRingsUri());
+ Map<Long, PGPKeyRing> allKeyRings = getPGPKeyRings(context, KeyRingData.buildSecretKeyRingUri());
int userIdRank = 0;
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
- operations.add(buildPublicUserIdOperations(context, keyRingRowId, userId, userIdRank));
+ operations.add(buildUserIdOperations(context, masterKeyId, userId, userIdRank));
// look through signatures for this specific key
for (PGPSignature cert : new IterableIterator<PGPSignature>(
@@ -244,8 +259,8 @@ public class ProviderHelper {
+ PgpKeyHelper.convertKeyIdToHex(cert.getKeyID())
);
// regardless of verification, save the certification
- operations.add(buildPublicCertOperations(
- context, keyRingRowId, userIdRank, masterKey.getKeyID(), cert, verified));
+ operations.add(buildCertOperations(
+ context, masterKeyId, userIdRank, masterKey.getKeyID(), cert, verified));
}
++userIdRank;
@@ -258,99 +273,74 @@ public class ProviderHelper {
} catch (OperationApplicationException e) {
Log.e(Constants.TAG, "applyBatch failed!", e);
}
+
+ // Save the saved keyring (if any)
+ if(secretRing != null) {
+ 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")
public static void saveKeyRing(Context context, PGPSecretKeyRing keyRing) throws IOException {
- PGPSecretKey masterKey = keyRing.getSecretKey();
- long masterKeyId = masterKey.getKeyID();
-
- Uri deleteUri = KeyRings.buildSecretKeyRingsByMasterKeyIdUri(Long.toString(masterKeyId));
-
- // get current _ID of key
- long currentRowId = -1;
- Cursor oldQuery = context.getContentResolver()
- .query(deleteUri, new String[]{KeyRings._ID}, null, null, null);
- if (oldQuery != null && oldQuery.moveToFirst()) {
- currentRowId = oldQuery.getLong(0);
- } else {
- Log.e(Constants.TAG, "Key could not be found! Something wrong is happening!");
- }
-
- // delete old version of this keyRing, which also deletes all keys and userIds on cascade
- try {
- context.getContentResolver().delete(deleteUri, null, null);
- } catch (UnsupportedOperationException e) {
- Log.e(Constants.TAG, "Key could not be deleted! Maybe we are creating a new one!", e);
- }
+ long masterKeyId = keyRing.getPublicKey().getKeyID();
+ // save secret keyring
ContentValues values = new ContentValues();
- // use exactly the same _ID again to replace key in-place.
- // NOTE: If we would not use the same _ID again,
- // getting back to the ViewKeyActivity would result in Nullpointer,
- // because the currently loaded key would be gone from the database
- if (currentRowId != -1) {
- values.put(KeyRings._ID, currentRowId);
- }
- values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
- values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
-
+ values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
+ values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded());
// insert new version of this keyRing
- Uri uri = KeyRings.buildSecretKeyRingsUri();
- Uri insertedUri = context.getContentResolver().insert(uri, values);
- long keyRingRowId = Long.valueOf(insertedUri.getLastPathSegment());
+ Uri uri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
+ context.getContentResolver().insert(uri, values);
- // 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;
- }
+ /**
+ * 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();
- int userIdRank = 0;
- for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
- operations.add(buildSecretUserIdOperations(context, keyRingRowId, userId, userIdRank));
- ++userIdRank;
- }
+ // delete secret keyring (so it isn't unnecessarily saved by public-saveKeyRing below)
+ context.getContentResolver().delete(KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null);
- try {
- context.getContentResolver().applyBatch(KeychainContract.CONTENT_AUTHORITY, operations);
- } catch (RemoteException e) {
- Log.e(Constants.TAG, "applyBatch failed!", e);
- } catch (OperationApplicationException e) {
- Log.e(Constants.TAG, "applyBatch failed!", e);
- }
+ // save public keyring
+ saveKeyRing(context, pubRing);
+ saveKeyRing(context, privRing);
}
/**
* Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing
*/
private static ContentProviderOperation buildPublicKeyOperations(Context context,
- long keyRingRowId, PGPPublicKey key, int rank) throws IOException {
+ long masterKeyId, PGPPublicKey key, int rank) throws IOException {
+
ContentValues values = new ContentValues();
+ values.put(Keys.MASTER_KEY_ID, masterKeyId);
+ values.put(Keys.RANK, rank);
+
values.put(Keys.KEY_ID, key.getKeyID());
- values.put(Keys.IS_MASTER_KEY, key.isMasterKey());
- values.put(Keys.ALGORITHM, key.getAlgorithm());
values.put(Keys.KEY_SIZE, key.getBitStrength());
- values.put(Keys.CAN_SIGN, PgpKeyHelper.isSigningKey(key));
+ values.put(Keys.ALGORITHM, key.getAlgorithm());
+ values.put(Keys.FINGERPRINT, key.getFingerprint());
+
+ values.put(Keys.CAN_CERTIFY, (PgpKeyHelper.isCertificationKey(key)));
+ values.put(Keys.CAN_SIGN, (PgpKeyHelper.isSigningKey(key)));
values.put(Keys.CAN_ENCRYPT, PgpKeyHelper.isEncryptionKey(key));
values.put(Keys.IS_REVOKED, key.isRevoked());
+
values.put(Keys.CREATION, PgpKeyHelper.getCreationDate(key).getTime() / 1000);
Date expiryDate = PgpKeyHelper.getExpiryDate(key);
if (expiryDate != null) {
values.put(Keys.EXPIRY, expiryDate.getTime() / 1000);
}
- values.put(Keys.KEY_RING_ROW_ID, keyRingRowId);
- values.put(Keys.KEY_DATA, key.getEncoded());
- values.put(Keys.RANK, rank);
- values.put(Keys.FINGERPRINT, key.getFingerprint());
- Uri uri = Keys.buildPublicKeysUri(Long.toString(keyRingRowId));
+ Uri uri = Keys.buildKeysUri(Long.toString(masterKeyId));
return ContentProviderOperation.newInsert(uri).withValues(values).build();
}
@@ -358,23 +348,23 @@ public class ProviderHelper {
/**
* Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing
*/
- private static ContentProviderOperation buildPublicCertOperations(Context context,
- long keyRingRowId,
+ private static ContentProviderOperation buildCertOperations(Context context,
+ long masterKeyId,
int rank,
long keyId,
PGPSignature cert,
boolean verified)
throws IOException {
ContentValues values = new ContentValues();
- values.put(Certs.KEY_RING_ROW_ID, keyRingRowId);
+ values.put(Certs.MASTER_KEY_ID, masterKeyId);
values.put(Certs.RANK, rank);
- values.put(Certs.KEY_ID, keyId);
values.put(Certs.KEY_ID_CERTIFIER, cert.getKeyID());
values.put(Certs.CREATION, cert.getCreationTime().getTime() / 1000);
+ values.put(Certs.EXPIRY, (String) null); // TODO
values.put(Certs.VERIFIED, verified);
values.put(Certs.KEY_DATA, cert.getEncoded());
- Uri uri = Certs.buildCertsByKeyRowIdUri(Long.toString(keyRingRowId));
+ Uri uri = Certs.buildCertsUri(Long.toString(masterKeyId));
return ContentProviderOperation.newInsert(uri).withValues(values).build();
}
@@ -382,351 +372,28 @@ public class ProviderHelper {
/**
* Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing
*/
- private static ContentProviderOperation buildPublicUserIdOperations(Context context,
- long keyRingRowId, String userId, int rank) {
- ContentValues values = new ContentValues();
- values.put(UserIds.KEY_RING_ROW_ID, keyRingRowId);
- values.put(UserIds.USER_ID, userId);
- values.put(UserIds.RANK, rank);
-
- Uri uri = UserIds.buildPublicUserIdsUri(Long.toString(keyRingRowId));
-
- return ContentProviderOperation.newInsert(uri).withValues(values).build();
- }
-
- /**
- * Build ContentProviderOperation to add PGPSecretKey to database corresponding to a keyRing
- */
- private static ContentProviderOperation buildSecretKeyOperations(Context context,
- long keyRingRowId, PGPSecretKey key, int rank) throws IOException {
- ContentValues values = new ContentValues();
-
- boolean hasPrivate = true;
- if (key.isMasterKey()) {
- if (key.isPrivateKeyEmpty()) {
- hasPrivate = false;
- }
- }
-
- values.put(Keys.KEY_ID, key.getKeyID());
- values.put(Keys.IS_MASTER_KEY, key.isMasterKey());
- values.put(Keys.ALGORITHM, key.getPublicKey().getAlgorithm());
- values.put(Keys.KEY_SIZE, key.getPublicKey().getBitStrength());
- values.put(Keys.CAN_CERTIFY, (PgpKeyHelper.isCertificationKey(key) && hasPrivate));
- values.put(Keys.CAN_SIGN, (PgpKeyHelper.isSigningKey(key) && hasPrivate));
- values.put(Keys.CAN_ENCRYPT, PgpKeyHelper.isEncryptionKey(key));
- values.put(Keys.IS_REVOKED, key.getPublicKey().isRevoked());
- values.put(Keys.CREATION, PgpKeyHelper.getCreationDate(key).getTime() / 1000);
- Date expiryDate = PgpKeyHelper.getExpiryDate(key);
- if (expiryDate != null) {
- values.put(Keys.EXPIRY, expiryDate.getTime() / 1000);
- }
- values.put(Keys.KEY_RING_ROW_ID, keyRingRowId);
- values.put(Keys.KEY_DATA, key.getEncoded());
- values.put(Keys.RANK, rank);
- values.put(Keys.FINGERPRINT, key.getPublicKey().getFingerprint());
-
- Uri uri = Keys.buildSecretKeysUri(Long.toString(keyRingRowId));
-
- return ContentProviderOperation.newInsert(uri).withValues(values).build();
- }
-
- /**
- * Build ContentProviderOperation to add SecretUserIds to database corresponding to a keyRing
- */
- private static ContentProviderOperation buildSecretUserIdOperations(Context context,
- long keyRingRowId, String userId, int rank) {
+ private static ContentProviderOperation buildUserIdOperations(Context context,
+ long masterKeyId, String userId, int rank) {
ContentValues values = new ContentValues();
- values.put(UserIds.KEY_RING_ROW_ID, keyRingRowId);
+ values.put(UserIds.MASTER_KEY_ID, masterKeyId);
values.put(UserIds.USER_ID, userId);
values.put(UserIds.RANK, rank);
- Uri uri = UserIds.buildSecretUserIdsUri(Long.toString(keyRingRowId));
+ Uri uri = UserIds.buildUserIdsUri(Long.toString(masterKeyId));
return ContentProviderOperation.newInsert(uri).withValues(values).build();
}
- /**
- * Private helper method
- */
- private static ArrayList<Long> getKeyRingsMasterKeyIds(Context context, Uri queryUri) {
- Cursor cursor = context.getContentResolver().query(queryUri,
- new String[]{KeyRings.MASTER_KEY_ID}, null, null, null);
-
- ArrayList<Long> masterKeyIds = new ArrayList<Long>();
- if (cursor != null) {
- int masterKeyIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
- if (cursor.moveToFirst()) {
- do {
- masterKeyIds.add(cursor.getLong(masterKeyIdCol));
- } while (cursor.moveToNext());
- }
- }
-
- if (cursor != null) {
- cursor.close();
- }
-
- return masterKeyIds;
- }
-
- /**
- * Private helper method
- */
- private static ArrayList<Long> getKeyRingsRowIds(Context context, Uri queryUri) {
- Cursor cursor = context.getContentResolver().query(queryUri,
- new String[]{KeyRings._ID}, null, null, null);
-
- ArrayList<Long> rowIds = new ArrayList<Long>();
- if (cursor != null) {
- int idCol = cursor.getColumnIndex(KeyRings._ID);
- if (cursor.moveToFirst()) {
- do {
- rowIds.add(cursor.getLong(idCol));
- } while (cursor.moveToNext());
- }
- }
-
- if (cursor != null) {
- cursor.close();
- }
-
- return rowIds;
- }
-
- /**
- * Retrieves ids of all SecretKeyRings
- */
- public static ArrayList<Long> getSecretKeyRingsMasterKeyIds(Context context) {
- Uri queryUri = KeyRings.buildSecretKeyRingsUri();
- return getKeyRingsMasterKeyIds(context, queryUri);
- }
-
- /**
- * Retrieves ids of all PublicKeyRings
- */
- public static ArrayList<Long> getPublicKeyRingsMasterKeyIds(Context context) {
- Uri queryUri = KeyRings.buildPublicKeyRingsUri();
- return getKeyRingsMasterKeyIds(context, queryUri);
- }
-
- /**
- * Retrieves ids of all SecretKeyRings
- */
- public static ArrayList<Long> getSecretKeyRingsRowIds(Context context) {
- Uri queryUri = KeyRings.buildSecretKeyRingsUri();
- return getKeyRingsRowIds(context, queryUri);
- }
-
- /**
- * Retrieves ids of all PublicKeyRings
- */
- public static ArrayList<Long> getPublicKeyRingsRowIds(Context context) {
- Uri queryUri = KeyRings.buildPublicKeyRingsUri();
- return getKeyRingsRowIds(context, queryUri);
- }
-
- public static void deletePublicKeyRing(Context context, long rowId) {
- ContentResolver cr = context.getContentResolver();
- cr.delete(KeyRings.buildPublicKeyRingsUri(Long.toString(rowId)), null, null);
- }
-
- public static void deleteSecretKeyRing(Context context, long rowId) {
- ContentResolver cr = context.getContentResolver();
- cr.delete(KeyRings.buildSecretKeyRingsUri(Long.toString(rowId)), null, null);
- }
-
- /**
- * Get master key id of keyring by its row id
- */
- public static long getPublicMasterKeyId(Context context, long keyRingRowId) {
- Uri queryUri = KeyRings.buildPublicKeyRingsUri(String.valueOf(keyRingRowId));
- return getMasterKeyId(context, queryUri);
- }
-
- /**
- * Get empty status of master key of keyring by its row id
- */
- public static boolean getSecretMasterKeyCanSign(Context context, long keyRingRowId) {
- Uri queryUri = KeyRings.buildSecretKeyRingsUri(String.valueOf(keyRingRowId));
- return getMasterKeyCanSign(context, queryUri);
- }
-
- /**
- * Private helper method to get master key private empty status of keyring by its row id
- */
- public static boolean getMasterKeyCanSign(Context context, Uri queryUri) {
- String[] projection = new String[]{
- KeyRings.MASTER_KEY_ID,
- "(SELECT COUNT(sign_keys." + Keys._ID + ") FROM " + Tables.KEYS
- + " AS sign_keys WHERE sign_keys." + Keys.KEY_RING_ROW_ID + " = "
- + KeychainDatabase.Tables.KEY_RINGS + "." + KeyRings._ID
- + " AND sign_keys." + Keys.CAN_SIGN + " = '1' AND " + Keys.IS_MASTER_KEY
- + " = 1) AS sign", };
-
- ContentResolver cr = context.getContentResolver();
- Cursor cursor = cr.query(queryUri, projection, null, null, null);
-
- long masterKeyId = -1;
- if (cursor != null && cursor.moveToFirst()) {
- int masterKeyIdCol = cursor.getColumnIndex("sign");
-
- masterKeyId = cursor.getLong(masterKeyIdCol);
- }
-
- if (cursor != null) {
- cursor.close();
- }
-
- return (masterKeyId > 0);
- }
-
- public static boolean hasSecretKeyByMasterKeyId(Context context, long masterKeyId) {
- Uri queryUri = KeyRings.buildSecretKeyRingsByMasterKeyIdUri(Long.toString(masterKeyId));
- // see if we can get our master key id back from the uri
- return getMasterKeyId(context, queryUri) == masterKeyId;
- }
-
- /**
- * Get master key id of keyring by its row id
- */
- public static long getSecretMasterKeyId(Context context, long keyRingRowId) {
- Uri queryUri = KeyRings.buildSecretKeyRingsUri(String.valueOf(keyRingRowId));
- return getMasterKeyId(context, queryUri);
- }
-
- /**
- * Get master key id of key
- */
- public static long getMasterKeyId(Context context, Uri queryUri) {
- String[] projection = new String[]{KeyRings.MASTER_KEY_ID};
- Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null);
-
- 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 long getRowId(Context context, Uri queryUri) {
- String[] projection = new String[]{KeyRings._ID};
- Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null);
-
- long rowId = 0;
- try {
- if (cursor != null && cursor.moveToFirst()) {
- int idCol = cursor.getColumnIndexOrThrow(KeyRings._ID);
-
- rowId = cursor.getLong(idCol);
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
-
- return rowId;
- }
-
- /**
- * Get fingerprint of key
- */
- public static byte[] getFingerprint(Context context, Uri queryUri) {
- String[] projection = new String[]{Keys.FINGERPRINT};
- Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null);
-
- byte[] fingerprint = null;
- try {
- if (cursor != null && cursor.moveToFirst()) {
- int col = cursor.getColumnIndexOrThrow(Keys.FINGERPRINT);
-
- fingerprint = cursor.getBlob(col);
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
-
- // FALLBACK: If fingerprint is not in database, get it from key blob!
- // this could happen if the key was saved by a previous version of Keychain!
- if (fingerprint == null) {
- Log.d(Constants.TAG, "FALLBACK: fingerprint is not in database, get it from key blob!");
-
- // get master key id
- projection = new String[]{KeyRings.MASTER_KEY_ID};
- cursor = context.getContentResolver().query(queryUri, projection, null, null, null);
- long masterKeyId = 0;
- try {
- if (cursor != null && cursor.moveToFirst()) {
- int col = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID);
-
- masterKeyId = cursor.getLong(col);
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
-
- PGPPublicKey key = ProviderHelper.getPGPPublicKeyByKeyId(context, masterKeyId);
- // if it is no public key get it from your own keys...
- if (key == null) {
- PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, masterKeyId);
- if (secretKey == null) {
- Log.e(Constants.TAG, "Key could not be found!");
- return null;
- }
- key = secretKey.getPublicKey();
- }
-
- fingerprint = key.getFingerprint();
- }
-
- return fingerprint;
- }
-
- public static String getUserId(Context context, Uri queryUri) {
- String[] projection = new String[]{UserIds.USER_ID};
- Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null);
-
- String userId = null;
- try {
- if (cursor != null && cursor.moveToFirst()) {
- int col = cursor.getColumnIndexOrThrow(UserIds.USER_ID);
-
- userId = cursor.getString(col);
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
-
- return userId;
- }
-
- public static ArrayList<String> getKeyRingsAsArmoredString(Context context, Uri uri,
- long[] masterKeyIds) {
+ public static ArrayList<String> getKeyRingsAsArmoredString(Context context, long[] masterKeyIds) {
ArrayList<String> output = new ArrayList<String>();
if (masterKeyIds != null && masterKeyIds.length > 0) {
- Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, uri, masterKeyIds);
+ Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, masterKeyIds);
if (cursor != null) {
- int masterIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
- int dataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA);
+ int masterIdCol = cursor.getColumnIndex(KeyRingData.MASTER_KEY_ID);
+ int dataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
if (cursor.moveToFirst()) {
do {
Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol));
@@ -776,48 +443,11 @@ public class ProviderHelper {
return null;
}
}
-
- 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) {
+ private static Cursor getCursorWithSelectedKeyringMasterKeyIds(Context context, long[] masterKeyIds) {
Cursor cursor = null;
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) {
if (i != 0) {
inMasterKeyList += ", ";
@@ -826,9 +456,9 @@ public class ProviderHelper {
}
inMasterKeyList += ")";
- cursor = context.getContentResolver().query(baseUri,
- new String[]{KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.KEY_RING_DATA},
- inMasterKeyList, null, null);
+ cursor = context.getContentResolver().query(KeyRingData.buildPublicKeyRingUri(), new String[] {
+ KeyRingData._ID, KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA
+ }, inMasterKeyList, null, null);
}
return cursor;
@@ -859,19 +489,28 @@ public class ProviderHelper {
ContentValues values = new ContentValues();
values.put(ApiApps.PACKAGE_NAME, appSettings.getPackageName());
values.put(ApiApps.PACKAGE_SIGNATURE, appSettings.getPackageSignature());
- values.put(ApiApps.KEY_ID, appSettings.getKeyId());
- values.put(ApiApps.COMPRESSION, appSettings.getCompression());
- values.put(ApiApps.ENCRYPTION_ALGORITHM, appSettings.getEncryptionAlgorithm());
- values.put(ApiApps.HASH_ALORITHM, appSettings.getHashAlgorithm());
+ return values;
+ }
+ private static ContentValues contentValueForApiAccounts(AccountSettings accSettings) {
+ ContentValues values = new ContentValues();
+ values.put(KeychainContract.ApiAccounts.ACCOUNT_NAME, accSettings.getAccountName());
+ values.put(KeychainContract.ApiAccounts.KEY_ID, accSettings.getKeyId());
+ values.put(KeychainContract.ApiAccounts.COMPRESSION, accSettings.getCompression());
+ values.put(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM, accSettings.getEncryptionAlgorithm());
+ values.put(KeychainContract.ApiAccounts.HASH_ALORITHM, accSettings.getHashAlgorithm());
return values;
}
public static void insertApiApp(Context context, AppSettings appSettings) {
- context.getContentResolver().insert(ApiApps.CONTENT_URI,
+ context.getContentResolver().insert(KeychainContract.ApiApps.CONTENT_URI,
contentValueForApiApps(appSettings));
}
+ public static void insertApiAccount(Context context, Uri uri, AccountSettings accSettings) {
+ context.getContentResolver().insert(uri, contentValueForApiAccounts(accSettings));
+ }
+
public static void updateApiApp(Context context, AppSettings appSettings, Uri uri) {
if (context.getContentResolver().update(uri, contentValueForApiApps(appSettings), null,
null) <= 0) {
@@ -879,30 +518,73 @@ public class ProviderHelper {
}
}
+ public static void updateApiAccount(Context context, AccountSettings accSettings, Uri uri) {
+ if (context.getContentResolver().update(uri, contentValueForApiAccounts(accSettings), null,
+ null) <= 0) {
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Must be an uri pointing to an account
+ *
+ * @param context
+ * @param uri
+ * @return
+ */
public static AppSettings getApiAppSettings(Context context, Uri uri) {
AppSettings settings = null;
Cursor cur = context.getContentResolver().query(uri, null, null, null, null);
if (cur != null && cur.moveToFirst()) {
settings = new AppSettings();
- settings.setPackageName(cur.getString(cur
- .getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME)));
- settings.setPackageSignature(cur.getBlob(cur
- .getColumnIndex(KeychainContract.ApiApps.PACKAGE_SIGNATURE)));
- settings.setKeyId(cur.getLong(cur.getColumnIndex(KeychainContract.ApiApps.KEY_ID)));
- settings.setCompression(cur.getInt(cur
- .getColumnIndexOrThrow(KeychainContract.ApiApps.COMPRESSION)));
- settings.setHashAlgorithm(cur.getInt(cur
- .getColumnIndexOrThrow(KeychainContract.ApiApps.HASH_ALORITHM)));
- settings.setEncryptionAlgorithm(cur.getInt(cur
- .getColumnIndexOrThrow(KeychainContract.ApiApps.ENCRYPTION_ALGORITHM)));
+ settings.setPackageName(cur.getString(
+ cur.getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME)));
+ settings.setPackageSignature(cur.getBlob(
+ cur.getColumnIndex(KeychainContract.ApiApps.PACKAGE_SIGNATURE)));
}
return settings;
}
+ public static AccountSettings getApiAccountSettings(Context context, Uri accountUri) {
+ AccountSettings settings = null;
+
+ Cursor cur = context.getContentResolver().query(accountUri, null, null, null, null);
+ if (cur != null && cur.moveToFirst()) {
+ settings = new AccountSettings();
+
+ settings.setAccountName(cur.getString(
+ cur.getColumnIndex(KeychainContract.ApiAccounts.ACCOUNT_NAME)));
+ settings.setKeyId(cur.getLong(
+ cur.getColumnIndex(KeychainContract.ApiAccounts.KEY_ID)));
+ settings.setCompression(cur.getInt(
+ cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.COMPRESSION)));
+ settings.setHashAlgorithm(cur.getInt(
+ cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.HASH_ALORITHM)));
+ settings.setEncryptionAlgorithm(cur.getInt(
+ cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM)));
+ }
+
+ return settings;
+ }
+
+ public static Set<Long> getAllKeyIdsForApp(Context context, Uri uri) {
+ Set<Long> keyIds = new HashSet<Long>();
+
+ Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
+ if (cursor != null) {
+ int keyIdColumn = cursor.getColumnIndex(KeychainContract.ApiAccounts.KEY_ID);
+ while (cursor.moveToNext()) {
+ keyIds.add(cursor.getLong(keyIdColumn));
+ }
+ }
+
+ return keyIds;
+ }
+
public static byte[] getApiAppSignature(Context context, String packageName) {
- Uri queryUri = KeychainContract.ApiApps.buildByPackageNameUri(packageName);
+ Uri queryUri = ApiApps.buildByPackageNameUri(packageName);
String[] projection = new String[]{ApiApps.PACKAGE_SIGNATURE};