From 5359205b5081134b31656696d426f8ed9a522679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 1 Feb 2014 16:17:33 +0100 Subject: [PATCH] Fix layout, add API notes to README, register fingerprint URIs, some reformatting (sry) --- OpenPGP-Keychain/src/main/AndroidManifest.xml | 14 + .../keychain/pgp/PgpKeyHelper.java | 39 +- .../keychain/provider/KeychainContract.java | 1 + .../keychain/provider/KeychainDatabase.java | 71 +- .../keychain/provider/KeychainProvider.java | 734 +++++++++--------- .../keychain/provider/ProviderHelper.java | 202 ++--- .../keychain/ui/ImportKeysActivity.java | 91 ++- .../keychain/ui/ImportKeysQrCodeFragment.java | 22 +- .../keychain/ui/ImportKeysServerFragment.java | 4 +- .../ui/adapter/ImportKeysListEntry.java | 2 +- .../ui/dialog/ShareQrCodeDialogFragment.java | 112 +-- .../res/layout/api_app_register_activity.xml | 4 +- .../layout/import_keys_clipboard_fragment.xml | 2 +- .../layout/import_keys_keyserver_fragment.xml | 2 +- .../res/layout/import_keys_nfc_fragment.xml | 4 +- .../layout/import_keys_qr_code_fragment.xml | 2 +- .../src/main/res/layout/key_server_export.xml | 4 +- .../src/main/res/layout/sign_key_activity.xml | 4 +- README.md | 10 +- 19 files changed, 650 insertions(+), 674 deletions(-) diff --git a/OpenPGP-Keychain/src/main/AndroidManifest.xml b/OpenPGP-Keychain/src/main/AndroidManifest.xml index 1863d2b62..b8ee23514 100644 --- a/OpenPGP-Keychain/src/main/AndroidManifest.xml +++ b/OpenPGP-Keychain/src/main/AndroidManifest.xml @@ -266,6 +266,20 @@ android:launchMode="singleTop" android:windowSoftInputMode="stateHidden" > + + + + + + + + + + + + + + diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index 7ab7aae3f..3fc63cda1 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -42,17 +42,6 @@ import android.content.Context; public class PgpKeyHelper { - /** - * Returns the last 9 chars of a fingerprint - * - * @param fingerprint - * String containing short or long fingerprint - * @return - */ - public static String shortifyFingerprint(String fingerprint) { - return fingerprint.substring(41); - } - public static Date getCreationDate(PGPPublicKey key) { return key.getCreationTime(); } @@ -175,10 +164,6 @@ public class PgpKeyHelper { return true; } - public static boolean isExpired(PGPSecretKey key) { - return isExpired(key.getPublicKey()); - } - public static Vector getUsableCertificationKeys(PGPSecretKeyRing keyRing) { Vector usableKeys = new Vector(); Vector signingKeys = getCertificationKeys(keyRing); @@ -460,12 +445,12 @@ public class PgpKeyHelper { * @param fp * @return */ - public static String convertFingerprintToHex(byte[] fp) { + public static String convertFingerprintToHex(byte[] fp, boolean chunked) { String fingerPrint = ""; for (int i = 0; i < fp.length; ++i) { - if (i != 0 && i % 10 == 0) { + if (chunked && i != 0 && i % 10 == 0) { fingerPrint += " "; - } else if (i != 0 && i % 2 == 0) { + } else if (chunked && i != 0 && i % 2 == 0) { fingerPrint += " "; } String chunk = Integer.toHexString((fp[i] + 256) % 256).toUpperCase(Locale.US); @@ -491,21 +476,21 @@ public class PgpKeyHelper { key = secretKey.getPublicKey(); } - return convertFingerprintToHex(key.getFingerprint()); + return convertFingerprintToHex(key.getFingerprint(), true); } public static boolean isSecretKeyPrivateEmpty(PGPSecretKey secretKey) { return secretKey.isPrivateKeyEmpty(); } - public static boolean isSecretKeyPrivateEmpty(Context context, long keyId) { - PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, keyId); - if (secretKey == null) { - Log.e(Constants.TAG, "Key could not be found!"); - return false; // could be a public key, assume it is not empty - } - return isSecretKeyPrivateEmpty(secretKey); - } +// public static boolean isSecretKeyPrivateEmpty(Context context, long keyId) { +// PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, keyId); +// if (secretKey == null) { +// Log.e(Constants.TAG, "Key could not be found!"); +// return false; // could be a public key, assume it is not empty +// } +// return isSecretKeyPrivateEmpty(secretKey); +// } public static String convertKeyIdToHex(long keyId) { String fingerPrint = Long.toHexString(keyId & 0xffffffffL).toUpperCase(Locale.US); 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 d2381f6f0..d8de30b37 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 @@ -45,6 +45,7 @@ public class KeychainContract { 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 { 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 60c5c91a8..3a00f3101 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 @@ -31,7 +31,7 @@ import android.provider.BaseColumns; public class KeychainDatabase extends SQLiteOpenHelper { private static final String DATABASE_NAME = "apg.db"; - private static final int DATABASE_VERSION = 6; + private static final int DATABASE_VERSION = 7; public interface Tables { String KEY_RINGS = "key_rings"; @@ -42,33 +42,45 @@ public class KeychainDatabase extends SQLiteOpenHelper { 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.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, " + + 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.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_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.PACKAGE_NAME + " TEXT UNIQUE, " + + ApiAppsColumns.PACKAGE_SIGNATURE + " BLOB, " + + ApiAppsColumns.KEY_ID + " INT64, " + + ApiAppsColumns.ENCRYPTION_ALGORITHM + " INTEGER, " + + ApiAppsColumns.HASH_ALORITHM + " INTEGER, " + ApiAppsColumns.COMPRESSION + " INTEGER)"; KeychainDatabase(Context context) { @@ -103,21 +115,24 @@ public class KeychainDatabase extends SQLiteOpenHelper { 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); - case 5: - // new column: package_signature - db.execSQL("DROP TABLE IF EXISTS " + Tables.API_APPS); - db.execSQL(CREATE_API_APPS); - - default: - break; + 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); + case 5: + // new column: package_signature + db.execSQL("DROP TABLE IF EXISTS " + Tables.API_APPS); + db.execSQL(CREATE_API_APPS); + case 6: + // new column: fingerprint + db.execSQL("ALTER TABLE " + Tables.KEYS + " ADD COLUMN " + KeysColumns.FINGERPRINT + + " BLOB;"); + default: + break; } } 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 70fb11e47..62fcf4f84 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 @@ -96,7 +96,7 @@ public class KeychainProvider extends ContentProvider { /** * public key rings - * + * *
          * key_rings/public
          * key_rings/public/#
@@ -128,7 +128,7 @@ public class KeychainProvider extends ContentProvider {
 
         /**
          * public keys
-         * 
+         *
          * 
          * key_rings/public/#/keys
          * key_rings/public/#/keys/#
@@ -143,7 +143,7 @@ public class KeychainProvider extends ContentProvider {
 
         /**
          * public user ids
-         * 
+         *
          * 
          * key_rings/public/#/user_ids
          * key_rings/public/#/user_ids/#
@@ -158,7 +158,7 @@ public class KeychainProvider extends ContentProvider {
 
         /**
          * secret key rings
-         * 
+         *
          * 
          * key_rings/secret
          * key_rings/secret/#
@@ -190,7 +190,7 @@ public class KeychainProvider extends ContentProvider {
 
         /**
          * secret keys
-         * 
+         *
          * 
          * key_rings/secret/#/keys
          * key_rings/secret/#/keys/#
@@ -205,7 +205,7 @@ public class KeychainProvider extends ContentProvider {
 
         /**
          * secret user ids
-         * 
+         *
          * 
          * key_rings/secret/#/user_ids
          * key_rings/secret/#/user_ids/#
@@ -228,7 +228,7 @@ public class KeychainProvider extends ContentProvider {
 
         /**
          * data stream
-         * 
+         *
          * 
          * data / _
          * 
@@ -240,7 +240,9 @@ public class KeychainProvider extends ContentProvider { private KeychainDatabase mApgDatabase; - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ @Override public boolean onCreate() { mUriMatcher = buildUriMatcher(); @@ -248,94 +250,96 @@ public class KeychainProvider extends ContentProvider { return true; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ @Override 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: + 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: - return KeyRings.CONTENT_ITEM_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: + return KeyRings.CONTENT_ITEM_TYPE; - case PUBLIC_KEY_RING_KEY: - case SECRET_KEY_RING_KEY: - return Keys.CONTENT_TYPE; + case PUBLIC_KEY_RING_KEY: + case SECRET_KEY_RING_KEY: + 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_KEY_BY_ROW_ID: + case SECRET_KEY_RING_KEY_BY_ROW_ID: + return Keys.CONTENT_ITEM_TYPE; - case PUBLIC_KEY_RING_USER_ID: - case SECRET_KEY_RING_USER_ID: - return UserIds.CONTENT_TYPE; + case PUBLIC_KEY_RING_USER_ID: + case SECRET_KEY_RING_USER_ID: + 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 PUBLIC_KEY_RING_USER_ID_BY_ROW_ID: + case SECRET_KEY_RING_USER_ID_BY_ROW_ID: + return UserIds.CONTENT_ITEM_TYPE; - case API_APPS: - return ApiApps.CONTENT_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; + case API_APPS_BY_ROW_ID: + case API_APPS_BY_PACKAGE_NAME: + return ApiApps.CONTENT_ITEM_TYPE; - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); + default: + throw new UnsupportedOperationException("Unknown uri: " + uri); } } /** * Returns type of the query (secret/public) - * + * * @param uri * @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_USER_ID_BY_ROW_ID: - type = KeyTypes.PUBLIC; - break; + 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_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 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; - default: - Log.e(Constants.TAG, "Unknown match " + match); - type = -1; - break; + default: + Log.e(Constants.TAG, "Unknown match " + match); + type = -1; + break; } return type; @@ -343,17 +347,20 @@ public class KeychainProvider extends ContentProvider { /** * Set result of query to specific columns, don't show blob column for external content provider - * + * * @return */ private HashMap getProjectionMapForKeyRings() { HashMap projectionMap = new HashMap(); projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID); - projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." - + KeyRingsColumns.MASTER_KEY_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.FINGERPRINT, Tables.KEYS + "." + KeysColumns.FINGERPRINT); + projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + UserIdsColumns.USER_ID); return projectionMap; @@ -361,7 +368,7 @@ public class KeychainProvider extends ContentProvider { /** * Set result of query to specific columns, don't show blob column for external content provider - * + * * @return */ private HashMap getProjectionMapForKeys() { @@ -386,22 +393,20 @@ public class KeychainProvider extends ContentProvider { } /** - * Builds default query for keyRings: KeyRings table is joined with UserIds - * - * @param qb - * @param match - * @param isMasterKey - * @param sortOrder - * @return + * Builds default query for keyRings: KeyRings table is joined with UserIds and Keys */ - private SQLiteQueryBuilder buildKeyRingQuery(SQLiteQueryBuilder qb, int match, String sortOrder) { + private SQLiteQueryBuilder buildKeyRingQuery(SQLiteQueryBuilder qb, int match) { // public or secret keyring qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = "); qb.appendWhereEscapeString(Integer.toString(getKeyType(match))); - // join keyrings with userIds to every keyring - qb.setTables(Tables.KEY_RINGS + " INNER JOIN " + Tables.USER_IDS + " ON " + "(" - + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.USER_IDS + "." + // 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')"); @@ -411,16 +416,11 @@ public class KeychainProvider extends ContentProvider { } /** - * Builds default query for keyRings: KeyRings table is joined with Keys and UserIds - * - * @param qb - * @param match - * @param isMasterKey - * @param sortOrder - * @return + * Builds default query for keyRings: KeyRings table is joined with UserIds and Keys + *

+ * Here only one key should be selected in the query to return a single keyring! */ - private SQLiteQueryBuilder buildKeyRingQueryWithKeys(SQLiteQueryBuilder qb, int match, - String sortOrder) { + private SQLiteQueryBuilder buildKeyRingQueryWithSpecificKey(SQLiteQueryBuilder qb, int match) { // public or secret keyring qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = "); qb.appendWhereEscapeString(Integer.toString(getKeyType(match))); @@ -438,11 +438,13 @@ public class KeychainProvider extends ContentProvider { return qb; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ @SuppressWarnings("deprecation") @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { + String sortOrder) { Log.v(Constants.TAG, "query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")"); SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); @@ -451,169 +453,169 @@ public class KeychainProvider extends ContentProvider { int match = mUriMatcher.match(uri); switch (match) { - case PUBLIC_KEY_RING: - case SECRET_KEY_RING: - qb = buildKeyRingQuery(qb, match, sortOrder); + case PUBLIC_KEY_RING: + case SECRET_KEY_RING: + qb = buildKeyRingQuery(qb, match); - if (TextUtils.isEmpty(sortOrder)) { - sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC"; - } - - break; - - case PUBLIC_KEY_RING_BY_ROW_ID: - case SECRET_KEY_RING_BY_ROW_ID: - qb = buildKeyRingQuery(qb, match, sortOrder); - - qb.appendWhere(" AND " + Tables.KEY_RINGS + "." + BaseColumns._ID + " = "); - qb.appendWhereEscapeString(uri.getLastPathSegment()); - - if (TextUtils.isEmpty(sortOrder)) { - sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC"; - } - - break; - - case PUBLIC_KEY_RING_BY_MASTER_KEY_ID: - case SECRET_KEY_RING_BY_MASTER_KEY_ID: - qb = buildKeyRingQuery(qb, match, sortOrder); - - qb.appendWhere(" AND " + Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getLastPathSegment()); - - if (TextUtils.isEmpty(sortOrder)) { - sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC"; - } - - break; - - case SECRET_KEY_RING_BY_KEY_ID: - case PUBLIC_KEY_RING_BY_KEY_ID: - qb = buildKeyRingQueryWithKeys(qb, match, sortOrder); - - qb.appendWhere(" AND " + Tables.KEYS + "." + KeysColumns.KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getLastPathSegment()); - - if (TextUtils.isEmpty(sortOrder)) { - sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC"; - } - - break; - - case SECRET_KEY_RING_BY_EMAILS: - case PUBLIC_KEY_RING_BY_EMAILS: - qb = buildKeyRingQuery(qb, match, sortOrder); - - 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 (TextUtils.isEmpty(sortOrder)) { + sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC"; } - if (i != 0) { - emailWhere += " OR "; - } - emailWhere += "tmp." + UserIdsColumns.USER_ID + " LIKE "; - // match '*', so it has to be at the *end* of the user id - emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">"); - gotCondition = true; - } - if (gotCondition) { + 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"; + } + + 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()); + + if (TextUtils.isEmpty(sortOrder)) { + sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC"; + } + + break; + + case SECRET_KEY_RING_BY_KEY_ID: + case PUBLIC_KEY_RING_BY_KEY_ID: + qb = buildKeyRingQueryWithSpecificKey(qb, match); + + qb.appendWhere(" AND " + Tables.KEYS + "." + KeysColumns.KEY_ID + " = "); + qb.appendWhereEscapeString(uri.getLastPathSegment()); + + if (TextUtils.isEmpty(sortOrder)) { + sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " 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 '*', 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 (" + emailWhere + + " = " + Tables.KEY_RINGS + "." + BaseColumns._ID + " AND (" + likeEmailWhere + "))"); - } - break; + break; - case SECRET_KEY_RING_BY_LIKE_EMAIL: - case PUBLIC_KEY_RING_BY_LIKE_EMAIL: - qb = buildKeyRingQuery(qb, match, sortOrder); + case PUBLIC_KEY_RING_KEY: + case SECRET_KEY_RING_KEY: + qb.setTables(Tables.KEYS); + qb.appendWhere(KeysColumns.TYPE + " = "); + qb.appendWhereEscapeString(Integer.toString(getKeyType(match))); - String likeEmail = uri.getLastPathSegment(); + qb.appendWhere(" AND " + KeysColumns.KEY_RING_ROW_ID + " = "); + qb.appendWhereEscapeString(uri.getPathSegments().get(2)); - String likeEmailWhere = "tmp." + UserIdsColumns.USER_ID + " LIKE " - + DatabaseUtils.sqlEscapeString("%<%" + likeEmail + "%>"); + qb.setProjectionMap(getProjectionMapForKeys()); - 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; - 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))); - case PUBLIC_KEY_RING_KEY: - case SECRET_KEY_RING_KEY: - 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 " + KeysColumns.KEY_RING_ROW_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(2)); + qb.appendWhere(" AND " + BaseColumns._ID + " = "); + qb.appendWhereEscapeString(uri.getLastPathSegment()); - qb.setProjectionMap(getProjectionMapForKeys()); + qb.setProjectionMap(getProjectionMapForKeys()); - break; + 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))); + case PUBLIC_KEY_RING_USER_ID: + case SECRET_KEY_RING_USER_ID: + qb.setTables(Tables.USER_IDS); + qb.appendWhere(UserIdsColumns.KEY_RING_ROW_ID + " = "); + qb.appendWhereEscapeString(uri.getPathSegments().get(2)); - qb.appendWhere(" AND " + KeysColumns.KEY_RING_ROW_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(2)); + break; - qb.appendWhere(" AND " + BaseColumns._ID + " = "); - qb.appendWhereEscapeString(uri.getLastPathSegment()); + 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.setProjectionMap(getProjectionMapForKeys()); + qb.appendWhere(" AND " + BaseColumns._ID + " = "); + qb.appendWhereEscapeString(uri.getLastPathSegment()); - break; + break; - case PUBLIC_KEY_RING_USER_ID: - case SECRET_KEY_RING_USER_ID: - qb.setTables(Tables.USER_IDS); - qb.appendWhere(UserIdsColumns.KEY_RING_ROW_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(2)); + case API_APPS: + qb.setTables(Tables.API_APPS); - break; + break; + case API_APPS_BY_ROW_ID: + qb.setTables(Tables.API_APPS); - 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(BaseColumns._ID + " = "); + qb.appendWhereEscapeString(uri.getLastPathSegment()); - qb.appendWhere(" AND " + BaseColumns._ID + " = "); - 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)); - break; + break; - case API_APPS: - qb.setTables(Tables.API_APPS); - - break; - case API_APPS_BY_ROW_ID: - qb.setTables(Tables.API_APPS); - - qb.appendWhere(BaseColumns._ID + " = "); - 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)); - - break; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); + default: + throw new IllegalArgumentException("Unknown URI " + uri); } @@ -634,14 +636,16 @@ public class KeychainProvider extends ContentProvider { Log.d(Constants.TAG, "Query: " + qb.buildQuery(projection, selection, selectionArgs, null, null, - orderBy, null)); + orderBy, null)); Log.d(Constants.TAG, "Cursor: " + DatabaseUtils.dumpCursorToString(c)); } return c; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ @Override public Uri insert(Uri uri, ContentValues values) { Log.d(Constants.TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")"); @@ -654,56 +658,56 @@ public class KeychainProvider extends ContentProvider { final int match = mUriMatcher.match(uri); switch (match) { - case PUBLIC_KEY_RING: - values.put(KeyRings.TYPE, KeyTypes.PUBLIC); + 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)); + rowId = db.insertOrThrow(Tables.KEY_RINGS, null, values); + rowUri = KeyRings.buildPublicKeyRingsUri(Long.toString(rowId)); + sendBroadcastDatabaseChange(getKeyType(match), getType(uri)); - break; - case PUBLIC_KEY_RING_KEY: - values.put(Keys.TYPE, KeyTypes.PUBLIC); + 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)); + rowId = db.insertOrThrow(Tables.KEYS, null, values); + rowUri = Keys.buildPublicKeysUri(Long.toString(rowId)); + sendBroadcastDatabaseChange(getKeyType(match), getType(uri)); - 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)); + 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)); - break; - case SECRET_KEY_RING: - values.put(KeyRings.TYPE, KeyTypes.SECRET); + 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)); + rowId = db.insertOrThrow(Tables.KEY_RINGS, null, values); + rowUri = KeyRings.buildSecretKeyRingsUri(Long.toString(rowId)); + sendBroadcastDatabaseChange(getKeyType(match), getType(uri)); - break; - case SECRET_KEY_RING_KEY: - values.put(Keys.TYPE, KeyTypes.SECRET); + 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)); + rowId = db.insertOrThrow(Tables.KEYS, null, values); + rowUri = Keys.buildSecretKeysUri(Long.toString(rowId)); + sendBroadcastDatabaseChange(getKeyType(match), getType(uri)); - break; - case SECRET_KEY_RING_USER_ID: - rowId = db.insertOrThrow(Tables.USER_IDS, null, values); - rowUri = UserIds.buildSecretUserIdsUri(Long.toString(rowId)); + break; + case SECRET_KEY_RING_USER_ID: + rowId = db.insertOrThrow(Tables.USER_IDS, null, values); + rowUri = UserIds.buildSecretUserIdsUri(Long.toString(rowId)); - break; - case API_APPS: - rowId = db.insertOrThrow(Tables.API_APPS, null, values); - rowUri = ApiApps.buildIdUri(Long.toString(rowId)); + break; + case API_APPS: + rowId = db.insertOrThrow(Tables.API_APPS, null, values); + rowUri = ApiApps.buildIdUri(Long.toString(rowId)); - break; - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); + break; + default: + throw new UnsupportedOperationException("Unknown uri: " + uri); } // notify of changes in db @@ -716,7 +720,9 @@ public class KeychainProvider extends ContentProvider { return rowUri; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { Log.v(Constants.TAG, "delete(uri=" + uri + ")"); @@ -728,45 +734,45 @@ public class KeychainProvider extends ContentProvider { 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(); - // 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)); - 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); - break; - case API_APPS_BY_ROW_ID: - count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, false, selection), - selectionArgs); - break; - case API_APPS_BY_PACKAGE_NAME: - count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, true, selection), - selectionArgs); - break; - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); + 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(); + // 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)); + 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); + break; + case API_APPS_BY_ROW_ID: + count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, false, selection), + selectionArgs); + break; + case API_APPS_BY_PACKAGE_NAME: + count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, true, selection), + selectionArgs); + break; + default: + throw new UnsupportedOperationException("Unknown uri: " + uri); } // notify of changes in db @@ -775,7 +781,9 @@ public class KeychainProvider extends ContentProvider { return count; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { Log.v(Constants.TAG, "update(uri=" + uri + ", values=" + values.toString() + ")"); @@ -787,54 +795,54 @@ public class KeychainProvider extends ContentProvider { 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(); + 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)); + 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(); + 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)); + 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_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); - break; - default: - throw new UnsupportedOperationException("Unknown uri: " + 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); + break; + default: + throw new UnsupportedOperationException("Unknown uri: " + uri); } // notify of changes in db @@ -850,13 +858,13 @@ public class KeychainProvider extends ContentProvider { /** * Build default selection statement for KeyRings. If no extra selection is specified only build * where clause with rowId - * + * * @param uri * @param selection * @return */ private String buildDefaultKeyRingsSelection(String defaultSelection, Integer keyType, - String selection) { + String selection) { String andType = ""; if (keyType != null) { andType = " AND " + KeyRingsColumns.TYPE + "=" + keyType; @@ -873,7 +881,7 @@ public class KeychainProvider extends ContentProvider { /** * Build default selection statement for Keys. If no extra selection is specified only build * where clause with rowId - * + * * @param uri * @param selection * @return @@ -901,7 +909,7 @@ public class KeychainProvider extends ContentProvider { /** * Build default selection statement for UserIds. If no extra selection is specified only build * where clause with rowId - * + * * @param uri * @param selection * @return @@ -924,7 +932,7 @@ public class KeychainProvider extends ContentProvider { /** * Build default selection statement for API apps. If no extra selection is specified only build * where clause with rowId - * + * * @param uri * @param selection * @return 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 10404e0ff..a1d7ad511 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 @@ -23,6 +23,8 @@ import java.util.ArrayList; import java.util.Date; import org.spongycastle.bcpg.ArmoredOutputStream; +import org.spongycastle.bcpg.UserAttributePacket; +import org.spongycastle.bcpg.UserAttributeSubpacket; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; @@ -55,10 +57,6 @@ public class ProviderHelper { /** * Private helper method to get PGPKeyRing from database - * - * @param context - * @param queryUri - * @return */ public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) { Cursor cursor = context.getContentResolver().query(queryUri, @@ -83,10 +81,6 @@ public class ProviderHelper { /** * Retrieves the actual PGPPublicKeyRing object from the database blob based on the rowId - * - * @param context - * @param rowId - * @return */ public static PGPPublicKeyRing getPGPPublicKeyRingByRowId(Context context, long rowId) { Uri queryUri = KeyRings.buildPublicKeyRingsUri(Long.toString(rowId)); @@ -95,10 +89,6 @@ public class ProviderHelper { /** * Retrieves the actual PGPPublicKeyRing object from the database blob based on the maserKeyId - * - * @param context - * @param masterKeyId - * @return */ public static PGPPublicKeyRing getPGPPublicKeyRingByMasterKeyId(Context context, long masterKeyId) { @@ -109,10 +99,6 @@ public class ProviderHelper { /** * Retrieves the actual PGPPublicKeyRing object from the database blob associated with a key * with this keyId - * - * @param context - * @param keyId - * @return */ public static PGPPublicKeyRing getPGPPublicKeyRingByKeyId(Context context, long keyId) { Uri queryUri = KeyRings.buildPublicKeyRingsByKeyIdUri(Long.toString(keyId)); @@ -122,10 +108,6 @@ public class ProviderHelper { /** * Retrieves the actual PGPPublicKey object from the database blob associated with a key with * this keyId - * - * @param context - * @param keyId - * @return */ public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long keyId) { PGPPublicKeyRing keyRing = getPGPPublicKeyRingByKeyId(context, keyId); @@ -138,10 +120,6 @@ public class ProviderHelper { /** * Retrieves the actual PGPSecretKeyRing object from the database blob based on the rowId - * - * @param context - * @param rowId - * @return */ public static PGPSecretKeyRing getPGPSecretKeyRingByRowId(Context context, long rowId) { Uri queryUri = KeyRings.buildSecretKeyRingsUri(Long.toString(rowId)); @@ -150,10 +128,6 @@ public class ProviderHelper { /** * Retrieves the actual PGPSecretKeyRing object from the database blob based on the maserKeyId - * - * @param context - * @param masterKeyId - * @return */ public static PGPSecretKeyRing getPGPSecretKeyRingByMasterKeyId(Context context, long masterKeyId) { @@ -164,10 +138,6 @@ public class ProviderHelper { /** * Retrieves the actual PGPSecretKeyRing object from the database blob associated with a key * with this keyId - * - * @param context - * @param keyId - * @return */ public static PGPSecretKeyRing getPGPSecretKeyRingByKeyId(Context context, long keyId) { Uri queryUri = KeyRings.buildSecretKeyRingsByKeyIdUri(Long.toString(keyId)); @@ -177,10 +147,6 @@ public class ProviderHelper { /** * Retrieves the actual PGPSecretKey object from the database blob associated with a key with * this keyId - * - * @param context - * @param keyId - * @return */ public static PGPSecretKey getPGPSecretKeyByKeyId(Context context, long keyId) { PGPSecretKeyRing keyRing = getPGPSecretKeyRingByKeyId(context, keyId); @@ -193,12 +159,6 @@ public class ProviderHelper { /** * Saves PGPPublicKeyRing with its keys and userIds in DB - * - * @param context - * @param keyRing - * @return - * @throws IOException - * @throws GeneralException */ @SuppressWarnings("unchecked") public static void saveKeyRing(Context context, PGPPublicKeyRing keyRing) throws IOException { @@ -263,12 +223,6 @@ public class ProviderHelper { /** * Saves PGPSecretKeyRing with its keys and userIds in DB - * - * @param context - * @param keyRing - * @return - * @throws IOException - * @throws GeneralException */ @SuppressWarnings("unchecked") public static void saveKeyRing(Context context, PGPSecretKeyRing keyRing) throws IOException { @@ -333,13 +287,6 @@ public class ProviderHelper { /** * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing - * - * @param context - * @param keyRingRowId - * @param key - * @param rank - * @return - * @throws IOException */ private static ContentProviderOperation buildPublicKeyOperations(Context context, long keyRingRowId, PGPPublicKey key, int rank) throws IOException { @@ -367,13 +314,6 @@ public class ProviderHelper { /** * Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing - * - * @param context - * @param keyRingRowId - * @param key - * @param rank - * @return - * @throws IOException */ private static ContentProviderOperation buildPublicUserIdOperations(Context context, long keyRingRowId, String userId, int rank) { @@ -389,13 +329,6 @@ public class ProviderHelper { /** * Build ContentProviderOperation to add PGPSecretKey to database corresponding to a keyRing - * - * @param context - * @param keyRingRowId - * @param key - * @param rank - * @return - * @throws IOException */ private static ContentProviderOperation buildSecretKeyOperations(Context context, long keyRingRowId, PGPSecretKey key, int rank) throws IOException { @@ -432,13 +365,6 @@ public class ProviderHelper { /** * Build ContentProviderOperation to add SecretUserIds to database corresponding to a keyRing - * - * @param context - * @param keyRingRowId - * @param key - * @param rank - * @return - * @throws IOException */ private static ContentProviderOperation buildSecretUserIdOperations(Context context, long keyRingRowId, String userId, int rank) { @@ -454,10 +380,6 @@ public class ProviderHelper { /** * Private helper method - * - * @param context - * @param queryUri - * @return */ private static ArrayList getKeyRingsMasterKeyIds(Context context, Uri queryUri) { Cursor cursor = context.getContentResolver().query(queryUri, @@ -482,9 +404,6 @@ public class ProviderHelper { /** * Retrieves ids of all SecretKeyRings - * - * @param context - * @return */ public static ArrayList getSecretKeyRingsMasterKeyIds(Context context) { Uri queryUri = KeyRings.buildSecretKeyRingsUri(); @@ -493,9 +412,6 @@ public class ProviderHelper { /** * Retrieves ids of all PublicKeyRings - * - * @param context - * @return */ public static ArrayList getPublicKeyRingsMasterKeyIds(Context context) { Uri queryUri = KeyRings.buildPublicKeyRingsUri(); @@ -514,10 +430,6 @@ public class ProviderHelper { /** * Get master key id of keyring by its row id - * - * @param context - * @param keyRingRowId - * @return */ public static long getPublicMasterKeyId(Context context, long keyRingRowId) { Uri queryUri = KeyRings.buildPublicKeyRingsUri(String.valueOf(keyRingRowId)); @@ -526,10 +438,6 @@ public class ProviderHelper { /** * Get empty status of master key of keyring by its row id - * - * @param context - * @param keyRingRowId - * @return */ public static boolean getSecretMasterKeyCanSign(Context context, long keyRingRowId) { Uri queryUri = KeyRings.buildSecretKeyRingsUri(String.valueOf(keyRingRowId)); @@ -538,11 +446,6 @@ public class ProviderHelper { /** * Private helper method to get master key private empty status of keyring by its row id - * - * @param context - * @param queryUri - * @param keyRingRowId - * @return */ private static boolean getMasterKeyCanSign(Context context, Uri queryUri, long keyRingRowId) { String[] projection = new String[]{ @@ -572,10 +475,6 @@ public class ProviderHelper { /** * Get master key id of keyring by its row id - * - * @param context - * @param keyRingRowId - * @return */ public static long getSecretMasterKeyId(Context context, long keyRingRowId) { Uri queryUri = KeyRings.buildSecretKeyRingsUri(String.valueOf(keyRingRowId)); @@ -583,41 +482,84 @@ public class ProviderHelper { } /** - * Private helper method to get master key id of keyring by its row id - * - * @param context - * @param queryUri - * @param keyRingRowId - * @return + * Get master key id of key */ public static long getMasterKeyId(Context context, Uri queryUri) { String[] projection = new String[]{KeyRings.MASTER_KEY_ID}; - - ContentResolver cr = context.getContentResolver(); - Cursor cursor = cr.query(queryUri, projection, null, null, null); + Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null); long masterKeyId = -1; - if (cursor != null && cursor.moveToFirst()) { - int masterKeyIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID); + try { + if (cursor != null && cursor.moveToFirst()) { + int masterKeyIdCol = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID); - masterKeyId = cursor.getLong(masterKeyIdCol); - } - - if (cursor != null) { - cursor.close(); + masterKeyId = cursor.getLong(masterKeyIdCol); + } + } finally { + if (cursor != null) { + cursor.close(); + } } return masterKeyId; } - public static ArrayList getPublicKeyRingsAsArmoredString(Context context, - long[] masterKeyIds) { - return getKeyRingsAsArmoredString(context, KeyRings.buildPublicKeyRingsUri(), masterKeyIds); - } + /** + * 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); - public static ArrayList getSecretKeyRingsAsArmoredString(Context context, - long[] masterKeyIds) { - return getKeyRingsAsArmoredString(context, KeyRings.buildSecretKeyRingsUri(), masterKeyIds); + 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 ArrayList getKeyRingsAsArmoredString(Context context, Uri uri, @@ -681,14 +623,6 @@ public class ProviderHelper { } } - public static byte[] getPublicKeyRingsAsByteArray(Context context, long[] masterKeyIds) { - return getKeyRingsAsByteArray(context, KeyRings.buildPublicKeyRingsUri(), masterKeyIds); - } - - public static byte[] getSecretKeyRingsAsByteArray(Context context, long[] masterKeyIds) { - return getKeyRingsAsByteArray(context, KeyRings.buildSecretKeyRingsUri(), masterKeyIds); - } - public static byte[] getKeyRingsAsByteArray(Context context, Uri uri, long[] masterKeyIds) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 1be5b8548..cccbcfa14 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -35,6 +36,7 @@ import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NfcAdapter; import android.os.Bundle; @@ -56,6 +58,8 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY"; public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_QR_CODE"; + public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = Constants.INTENT_PREFIX + + "IMPORT_KEY_FROM_KEYSERVER"; // Actions for internal use only: public static final String ACTION_IMPORT_KEY_FROM_FILE = Constants.INTENT_PREFIX @@ -63,24 +67,21 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi public static final String ACTION_IMPORT_KEY_FROM_NFC = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_NFC"; - // only used by IMPORT + // only used by ACTION_IMPORT_KEY public static final String EXTRA_KEY_BYTES = "key_bytes"; - // TODO: import keys from server - // public static final String EXTRA_KEY_ID = "keyId"; + // only used by ACTION_IMPORT_KEY_FROM_KEYSERVER + public static final String EXTRA_QUERY = "query"; + + public static final String FINGERPRINT_SCHEME = "openpgp4fpr"; protected boolean mDeleteAfterImport = false; - FileDialogFragment mFileDialog; - ImportKeysListFragment mListFragment; - OnNavigationListener mOnNavigationListener; - String[] mNavigationStrings; - - Fragment mCurrentFragment; - - BootstrapButton mImportButton; - - // BootstrapButton mImportSignUploadButton; + // view + private ImportKeysListFragment mListFragment; + private String[] mNavigationStrings; + private Fragment mCurrentFragment; + private BootstrapButton mImportButton; @Override protected void onCreate(Bundle savedInstanceState) { @@ -95,21 +96,11 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi importKeys(); } }); - // mImportSignUploadButton = (BootstrapButton) findViewById(R.id.import_sign_and_upload); - // mImportSignUploadButton.setOnClickListener(new OnClickListener() { - // @Override - // public void onClick(View v) { - // signAndUploadOnClick(); - // } - // }); getSupportActionBar().setDisplayShowTitleEnabled(false); setupDrawerNavigation(savedInstanceState); - // set actionbar without home button if called from another app - // ActionBarHelper.setBackButton(this); - // set drop down navigation mNavigationStrings = getResources().getStringArray(R.array.import_action_list); Context context = getSupportActionBar().getThemedContext(); @@ -125,6 +116,8 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi protected void handleActions(Bundle savedInstanceState, Intent intent) { String action = intent.getAction(); Bundle extras = intent.getExtras(); + Uri dataUri = intent.getData(); + String scheme = intent.getScheme(); if (extras == null) { extras = new Bundle(); @@ -139,6 +132,15 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi action = ACTION_IMPORT_KEY; } + /** + * Scanning a fingerprint directly with Barcode Scanner + */ + if (scheme != null && scheme.toLowerCase(Locale.ENGLISH).equals(FINGERPRINT_SCHEME)) { + getSupportActionBar().setSelectedNavigationItem(0); + loadFragment(ImportKeysQrCodeFragment.class, null, mNavigationStrings[0]); + loadFromFingerprintUri(dataUri); + } + /** * Keychain's own Actions */ @@ -160,14 +162,25 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi // directly load data startListFragment(savedInstanceState, importData, null); } + } else if (ACTION_IMPORT_KEY_FROM_KEYSERVER.equals(action)) { + if (!extras.containsKey(EXTRA_QUERY)) { + Log.e(Constants.TAG, "IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query' extra!"); + return; + } + + String query = extras.getString(EXTRA_QUERY); + + // TODO: implement KEYSERVER! + } else { - // Internal actions + // Other actions startListFragment(savedInstanceState, null, null); if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) { getSupportActionBar().setSelectedNavigationItem(1); loadFragment(ImportKeysFileFragment.class, null, mNavigationStrings[1]); } else if (ACTION_IMPORT_KEY_FROM_QR_CODE.equals(action)) { + // also exposed in AndroidManifest getSupportActionBar().setSelectedNavigationItem(2); loadFragment(ImportKeysQrCodeFragment.class, null, mNavigationStrings[2]); } else if (ACTION_IMPORT_KEY_FROM_NFC.equals(action)) { @@ -239,6 +252,23 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi ft.commit(); } + public void loadFromFingerprintUri(Uri dataUri) { + String fingerprint = dataUri.toString().split(":")[1].toLowerCase(Locale.ENGLISH); + + Log.d(Constants.TAG, "fingerprint: " + fingerprint); + + if (fingerprint.length() < 16) { + Toast.makeText(this, R.string.import_qr_code_too_short_fingerprint, + Toast.LENGTH_LONG).show(); + return; + } + + Intent queryIntent = new Intent(this, KeyServerQueryActivity.class); + queryIntent.setAction(KeyServerQueryActivity.ACTION_LOOK_UP_KEY_ID); + queryIntent.putExtra(KeyServerQueryActivity.EXTRA_FINGERPRINT, fingerprint); + startActivity(queryIntent); + } + public void loadCallback(byte[] importData, String importFilename) { mListFragment.loadNew(importData, importFilename); } @@ -413,19 +443,6 @@ public class ImportKeysActivity extends DrawerActivity implements OnNavigationLi } } - public void importOnClick() { - importKeys(); - } - - // public void signAndUploadOnClick() { - // // first, import! - // // importOnClick(view); - // - // // TODO: implement sign and upload! - // Toast.makeText(ImportKeysActivity.this, "Not implemented right now!", Toast.LENGTH_SHORT) - // .show(); - // } - /** * NFC */ diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java index 3ede641d3..9d7d16a42 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java @@ -26,6 +26,7 @@ import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4; import org.sufficientlysecure.keychain.util.Log; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; @@ -101,8 +102,8 @@ public class ImportKeysQrCodeFragment extends Fragment { Log.d(Constants.TAG, "scanResult content: " + scanResult.getContents()); // look if it's fingerprint only - if (scanResult.getContents().toLowerCase(Locale.ENGLISH).startsWith("openpgp4fpr")) { - importFingerprint(scanResult.getContents().toLowerCase(Locale.ENGLISH)); + if (scanResult.getContents().toLowerCase(Locale.ENGLISH).startsWith(ImportKeysActivity.FINGERPRINT_SCHEME)) { + importFingerprint(Uri.parse(scanResult.getContents())); return; } @@ -128,21 +129,8 @@ public class ImportKeysQrCodeFragment extends Fragment { } } - private void importFingerprint(String uri) { - String fingerprint = uri.split(":")[1]; - - Log.d(Constants.TAG, "fingerprint: " + fingerprint); - - if (fingerprint.length() < 16) { - Toast.makeText(getActivity(), R.string.import_qr_code_too_short_fingerprint, - Toast.LENGTH_LONG).show(); - return; - } - - Intent queryIntent = new Intent(getActivity(), KeyServerQueryActivity.class); - queryIntent.setAction(KeyServerQueryActivity.ACTION_LOOK_UP_KEY_ID); - queryIntent.putExtra(KeyServerQueryActivity.EXTRA_FINGERPRINT, fingerprint); - startActivity(queryIntent); + public void importFingerprint(Uri dataUri) { + mImportActivity.loadFromFingerprintUri(dataUri); } private void importParts(String[] parts) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java index c985f1f60..5d8885e2f 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java @@ -32,10 +32,12 @@ import com.beardedhen.androidbootstrap.BootstrapButton; public class ImportKeysServerFragment extends Fragment { private BootstrapButton mButton; + String mQuery; + /** * Creates new instance of this fragment */ - public static ImportKeysServerFragment newInstance() { + public static ImportKeysServerFragment newInstance(String query) { ImportKeysServerFragment frag = new ImportKeysServerFragment(); Bundle args = new Bundle(); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java index 1a100a585..3ad82ea0b 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java @@ -83,7 +83,7 @@ public class ImportKeysListEntry implements Serializable { this.revoked = pgpKeyRing.getPublicKey().isRevoked(); this.fingerPrint = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey() - .getFingerprint()); + .getFingerprint(), true); this.hexKeyId = PgpKeyHelper.convertKeyIdToHex(keyId); this.bitStrength = pgpKeyRing.getPublicKey().getBitStrength(); int algorithm = pgpKeyRing.getPublicKey().getAlgorithm(); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java index 771816bfc..48ed5310b 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java @@ -40,12 +40,14 @@ import android.widget.TextView; import com.actionbarsherlock.app.SherlockDialogFragment; public class ShareQrCodeDialogFragment extends SherlockDialogFragment { - private static final String ARG_URI = "uri"; + private static final String ARG_KEY_URI = "uri"; private static final String ARG_FINGERPRINT_ONLY = "fingerprint_only"; private ImageView mImage; private TextView mText; + private boolean mFingerprintOnly; + private ArrayList mContentList; private int mCounter; @@ -53,15 +55,11 @@ public class ShareQrCodeDialogFragment extends SherlockDialogFragment { /** * Creates new instance of this dialog fragment - * - * @param content - * Content to be shared via QR Codes - * @return */ public static ShareQrCodeDialogFragment newInstance(Uri dataUri, boolean fingerprintOnly) { ShareQrCodeDialogFragment frag = new ShareQrCodeDialogFragment(); Bundle args = new Bundle(); - args.putParcelable(ARG_URI, dataUri); + args.putParcelable(ARG_KEY_URI, dataUri); args.putBoolean(ARG_FINGERPRINT_ONLY, fingerprintOnly); frag.setArguments(args); @@ -76,8 +74,8 @@ public class ShareQrCodeDialogFragment extends SherlockDialogFragment { public Dialog onCreateDialog(Bundle savedInstanceState) { final Activity activity = getActivity(); - Uri dataUri = getArguments().getParcelable(ARG_URI); - boolean fingerprintOnly = getArguments().getBoolean(ARG_FINGERPRINT_ONLY); + Uri dataUri = getArguments().getParcelable(ARG_KEY_URI); + mFingerprintOnly = getArguments().getBoolean(ARG_FINGERPRINT_ONLY); AlertDialog.Builder alert = new AlertDialog.Builder(activity); @@ -90,29 +88,31 @@ public class ShareQrCodeDialogFragment extends SherlockDialogFragment { mImage = (ImageView) view.findViewById(R.id.share_qr_code_dialog_image); mText = (TextView) view.findViewById(R.id.share_qr_code_dialog_text); - // TODO - long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri); - String content = null; - if (fingerprintOnly) { + if (mFingerprintOnly) { content = "openpgp4fpr:"; - String fingerprint = PgpKeyHelper.convertKeyToHex(masterKeyId); - - mText.setText(getString(R.string.share_qr_code_dialog_fingerprint_text) + " " - + fingerprint); + byte[] fingerprintBlob = ProviderHelper.getFingerprint(getActivity(), dataUri); + String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob, false); + mText.setText(getString(R.string.share_qr_code_dialog_fingerprint_text) + " " + fingerprint); content = content + fingerprint; Log.d(Constants.TAG, "content: " + content); alert.setPositiveButton(R.string.btn_okay, null); + + setQrCode(content); } else { mText.setText(R.string.share_qr_code_dialog_start); + // TODO + long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri); + + // get public keyring as ascii armored string ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString( - getActivity(), dataUri, new long[] { masterKeyId }); + getActivity(), dataUri, new long[]{masterKeyId}); // TODO: binary? @@ -122,55 +122,61 @@ public class ShareQrCodeDialogFragment extends SherlockDialogFragment { // http://stackoverflow.com/questions/2620444/how-to-prevent-a-dialog-from-closing-when-a-button-is-clicked alert.setPositiveButton(R.string.btn_next, null); alert.setNegativeButton(android.R.string.cancel, null); + + mContentList = splitString(content, 1000); + + // start with first + mCounter = 0; + updatePartsQrCode(); } - mContentList = splitString(content, 1000); - - // start with first - mCounter = 0; - updateQrCode(); - return alert.create(); } @Override public void onResume() { super.onResume(); - AlertDialog alertDialog = (AlertDialog) getDialog(); - final Button backButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE); - final Button nextButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); - backButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mCounter > 0) { - mCounter--; - updateQrCode(); - updateDialog(backButton, nextButton); - } else { - dismiss(); - } - } - }); - nextButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { + if (!mFingerprintOnly) { + AlertDialog alertDialog = (AlertDialog) getDialog(); + final Button backButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE); + final Button nextButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); - if (mCounter < mContentList.size() - 1) { - mCounter++; - updateQrCode(); - updateDialog(backButton, nextButton); - } else { - dismiss(); + backButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mCounter > 0) { + mCounter--; + updatePartsQrCode(); + updateDialog(backButton, nextButton); + } else { + dismiss(); + } } - } - }); + }); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + if (mCounter < mContentList.size() - 1) { + mCounter++; + updatePartsQrCode(); + updateDialog(backButton, nextButton); + } else { + dismiss(); + } + } + }); + } } - private void updateQrCode() { + private void updatePartsQrCode() { // Content: ,, - mImage.setImageBitmap(QrCodeUtils.getQRCodeBitmap(mCounter + "," + mContentList.size() - + "," + mContentList.get(mCounter), QR_CODE_SIZE)); + setQrCode(mCounter + "," + mContentList.size() + "," + mContentList.get(mCounter)); + } + + private void setQrCode(String data) { + mImage.setImageBitmap(QrCodeUtils.getQRCodeBitmap(data, QR_CODE_SIZE)); } private void updateDialog(Button backButton, Button nextButton) { @@ -191,7 +197,7 @@ public class ShareQrCodeDialogFragment extends SherlockDialogFragment { /** * Split String by number of characters - * + * * @param text * @param size * @return diff --git a/OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml b/OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml index 2cbc81cf7..79daef590 100644 --- a/OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml +++ b/OpenPGP-Keychain/src/main/res/layout/api_app_register_activity.xml @@ -3,8 +3,8 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" android:orientation="vertical" >