From 6d1137190529dc7add74926cea52c377883319be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 6 Apr 2014 12:57:42 +0200 Subject: Rename folder structure from OpenPGP Keychain to OpenKeychain --- .../keychain/provider/KeychainContract.java | 297 -------- .../keychain/provider/KeychainDatabase.java | 301 --------- .../keychain/provider/KeychainProvider.java | 752 --------------------- .../provider/KeychainServiceBlobContract.java | 40 -- .../provider/KeychainServiceBlobDatabase.java | 47 -- .../provider/KeychainServiceBlobProvider.java | 162 ----- .../keychain/provider/ProviderHelper.java | 673 ------------------ 7 files changed, 2272 deletions(-) delete mode 100644 OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java delete mode 100644 OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java delete mode 100644 OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java delete mode 100644 OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java delete mode 100644 OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java delete mode 100644 OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java delete mode 100644 OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider') 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 deleted file mode 100644 index fc25faecd..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -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 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 ALGORITHM = "algorithm"; - String FINGERPRINT = "fingerprint"; - - String KEY_SIZE = "key_size"; - 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"; - } - - interface UserIdsColumns { - 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"; // ONLY used for sorting! no key, no nothing! - String IS_PRIMARY = "is_primary"; - String IS_REVOKED = "is_revoked"; - } - - interface CertsColumns { - String MASTER_KEY_ID = "master_key_id"; - String RANK = "rank"; - String KEY_ID_CERTIFIER = "key_id_certifier"; - String TYPE = "type"; - String VERIFIED = "verified"; - String CREATION = "creation"; - String DATA = "data"; - } - - 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 { - public static final int PUBLIC = 0; - public static final int SECRET = 1; - } - - public static final String CONTENT_AUTHORITY = Constants.PACKAGE_NAME + ".provider"; - - private static final Uri BASE_CONTENT_URI_INTERNAL = Uri - .parse("content://" + CONTENT_AUTHORITY); - - public static final String BASE_KEY_RINGS = "key_rings"; - public static final String BASE_DATA = "data"; - - public static final String PATH_UNIFIED = "unified"; - - 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_ACCOUNTS = "accounts"; - - public static class KeyRings implements BaseColumns, KeysColumns, UserIdsColumns { - public static final String MASTER_KEY_ID = KeysColumns.MASTER_KEY_ID; - public static final String IS_REVOKED = KeysColumns.IS_REVOKED; - public static final String VERIFIED = CertsColumns.VERIFIED; - public static final String HAS_SECRET = "has_secret"; - - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_KEY_RINGS).build(); - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring"; - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring"; - - public static Uri buildUnifiedKeyRingsUri() { - return CONTENT_URI.buildUpon().appendPath(PATH_UNIFIED).build(); - } - - public static Uri buildGenericKeyRingUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).build(); - } - public static Uri buildUnifiedKeyRingUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_UNIFIED).build(); - } - public static Uri buildUnifiedKeyRingUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_UNIFIED).build(); - } - - public static Uri buildUnifiedKeyRingsFindByEmailUri(String email) { - return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_EMAIL).appendPath(email).build(); - } - public static Uri buildUnifiedKeyRingsFindBySubkeyUri(String subkey) { - return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_SUBKEY).appendPath(subkey).build(); - } - - } - - public static class KeyRingData implements KeyRingsColumns, BaseColumns { - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_KEY_RINGS).build(); - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring_data"; - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring_data"; - - public static Uri buildPublicKeyRingUri() { - return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).build(); - } - public static Uri buildPublicKeyRingUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_PUBLIC).build(); - } - public static Uri buildPublicKeyRingUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_PUBLIC).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 { - 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.sufficientlysecure.openkeychain.key"; - - /** - * Use if a single item is returned - */ - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key"; - - public static Uri buildKeysUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).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 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.sufficientlysecure.openkeychain.user_id"; - - /** - * Use if a single item is returned - */ - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.user_id"; - - public static Uri buildUserIdsUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_USER_IDS).build(); - } - public static Uri buildUserIdsUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).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(); - - /** - * Use if multiple items get returned - */ - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.api_apps"; - - /** - * 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 buildByPackageNameUri(String packageName) { - return CONTENT_URI.buildUpon().appendEncodedPath(packageName).build(); - } - } - - 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.sufficientlysecure.openkeychain.api_app.accounts"; - - /** - * Use if a single item is returned - */ - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.api_app.account"; - - public static Uri buildBaseUri(String packageName) { - return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendPath(PATH_ACCOUNTS) - .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 String USER_ID = UserIdsColumns.USER_ID; - public static final String SIGNER_UID = "signer_user_id"; - - public static final int VERIFIED_SECRET = 1; - public static final int VERIFIED_SELF = 2; - - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_KEY_RINGS).build(); - - public static Uri buildCertsUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_CERTS).build(); - } - public static Uri buildCertsSpecificUri(String masterKeyId, String rank, String certifier) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_CERTS).appendPath(rank).appendPath(certifier).build(); - } - public static Uri buildCertsUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_CERTS).build(); - } - - } - - public static class DataStream { - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_DATA).build(); - - public static Uri buildDataStreamUri(String streamFilename) { - return CONTENT_URI.buildUpon().appendPath(streamFilename).build(); - } - } - - private KeychainContract() { - } -} 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 deleted file mode 100644 index 8674ad94b..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -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 = "openkeychain.db"; - private static final int DATABASE_VERSION = 1; - static Boolean apgHack = false; - - public interface Tables { - String KEY_RINGS_PUBLIC = "keyrings_public"; - String KEY_RINGS_SECRET = "keyrings_secret"; - String KEYS = "keys"; - String USER_IDS = "user_ids"; - String CERTS = "certs"; - String API_APPS = "api_apps"; - String API_ACCOUNTS = "api_accounts"; - } - - 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.IS_REVOKED + " 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.TYPE + " INTEGER, " - + CertsColumns.VERIFIED + " INTEGER, " - + CertsColumns.CREATION + " INTEGER, " - - + CertsColumns.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 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(apgHack) { - if(!apgHack) { - iAmIt = true; - apgHack = 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_KEYRINGS_PUBLIC); - db.execSQL(CREATE_KEYRINGS_SECRET); - db.execSQL(CREATE_KEYS); - db.execSQL(CREATE_USER_IDS); - db.execSQL(CREATE_CERTS); - db.execSQL(CREATE_API_APPS); - db.execSQL(CREATE_API_APPS_ACCOUNTS); - } - - @Override - public void onOpen(SQLiteDatabase db) { - super.onOpen(db); - 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 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, a master_key_id and a type column, the latter of - * which should be 1 for secret keys and 0 for public 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; - } - } - } - - 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 = null; - try { - // we insert in two steps: first, all public keys that have secret keys - c = db.rawQuery("SELECT key_ring_data FROM key_rings WHERE type = 1 OR EXISTS (" - + " SELECT 1 FROM key_rings d2 WHERE key_rings.master_key_id = d2.master_key_id" - + " AND d2.type = 1) ORDER BY type ASC", null); - Log.d(Constants.TAG, "Importing " + c.getCount() + " secret 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!"); - } - } - - // afterwards, insert all keys, starting with public keys that have secret keys, then - // secret keys, then all others. this order is necessary to ensure all certifications - // are recognized properly. - c = db.rawQuery("SELECT key_ring_data FROM key_rings ORDER BY (type = 0 AND EXISTS (" - + " SELECT 1 FROM key_rings d2 WHERE key_rings.master_key_id = d2.master_key_id AND" - + " d2.type = 1)) DESC, type DESC", null); - // 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 deleted file mode 100644 index 9b9e4991d..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ /dev/null @@ -1,752 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * Copyright (C) 2010 Thialfihar - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.provider; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.content.UriMatcher; -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.database.sqlite.SQLiteConstraintException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteQueryBuilder; -import android.net.Uri; -import android.text.TextUtils; - -import org.sufficientlysecure.keychain.Constants; -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; - -import java.util.Arrays; -import java.util.HashMap; - -public class KeychainProvider extends ContentProvider { - - 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 KEY_RING_CERTS_SPECIFIC = 206; - - private static final int API_APPS = 301; - 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 KEY_RINGS_FIND_BY_EMAIL = 400; - private static final int KEY_RINGS_FIND_BY_SUBKEY = 401; - - // private static final int DATA_STREAM = 501; - - protected UriMatcher mUriMatcher; - - /** - * Build and return a {@link UriMatcher} that catches all {@link Uri} variations supported by - * this {@link ContentProvider}. - */ - protected UriMatcher buildUriMatcher() { - final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); - - String authority = KeychainContract.CONTENT_AUTHORITY; - - /** - * list key_rings - * - *
-         * key_rings/unified
-         * key_rings/public
-         * 
- */ - 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); - - /** - * find by criteria other than master key id - * - * key_rings/find/email/_ - * key_rings/find/subkey/_ - * - */ - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" - + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_EMAIL + "/*", - KEY_RINGS_FIND_BY_EMAIL); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" - + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_SUBKEY + "/*", - KEY_RINGS_FIND_BY_SUBKEY); - - /** - * list key_ring specifics - * - *
-         * key_rings/_/unified
-         * key_rings/_/keys
-         * key_rings/_/user_ids
-         * key_rings/_/public
-         * key_rings/_/secret
-         * key_rings/_/certs
-         * key_rings/_/certs/_/_
-         * 
- */ - 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); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" - + KeychainContract.PATH_CERTS + "/*/*", - KEY_RING_CERTS_SPECIFIC); - - /** - * API apps - * - *
-         * api_apps
-         * api_apps/_ (package name)
-         *
-         * api_apps/_/accounts
-         * api_apps/_/accounts/_ (account name)
-         * 
- */ - matcher.addURI(authority, KeychainContract.BASE_API_APPS, API_APPS); - matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*", API_APPS_BY_PACKAGE_NAME); - - 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 - * - *
-         * data / _
-         * 
- */ - // matcher.addURI(authority, KeychainContract.BASE_DATA + "/*", DATA_STREAM); - - return matcher; - } - - private KeychainDatabase mKeychainDatabase; - - /** - * {@inheritDoc} - */ - @Override - public boolean onCreate() { - mUriMatcher = buildUriMatcher(); - return true; - } - - public KeychainDatabase getDb() { - if(mKeychainDatabase == null) - mKeychainDatabase = new KeychainDatabase(getContext()); - return mKeychainDatabase; - } - - /** - * {@inheritDoc} - */ - @Override - public String getType(Uri uri) { - final int match = mUriMatcher.match(uri); - switch (match) { - case KEY_RING_PUBLIC: - return KeyRings.CONTENT_ITEM_TYPE; - - case KEY_RING_KEYS: - return Keys.CONTENT_TYPE; - - case KEY_RING_USER_IDS: - return UserIds.CONTENT_TYPE; - - case KEY_RING_SECRET: - return KeyRings.CONTENT_ITEM_TYPE; - - case API_APPS: - return ApiApps.CONTENT_TYPE; - - case API_APPS_BY_PACKAGE_NAME: - return ApiApps.CONTENT_ITEM_TYPE; - - case API_ACCOUNTS: - return ApiAccounts.CONTENT_TYPE; - - case API_ACCOUNTS_BY_ACCOUNT_NAME: - return ApiAccounts.CONTENT_ITEM_TYPE; - - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); - } - } - - /** - * {@inheritDoc} - */ - @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(); - - int match = mUriMatcher.match(uri); - - // all query() parameters, for good measure - String groupBy = null, having = null; - - switch (match) { - case KEY_RING_UNIFIED: - case KEY_RINGS_UNIFIED: - case KEY_RINGS_FIND_BY_EMAIL: - case KEY_RINGS_FIND_BY_SUBKEY: { - HashMap projectionMap = new HashMap(); - 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, Tables.KEYS + "." + 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, Tables.KEYS + "." + 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.VERIFIED, KeyRings.VERIFIED); - 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 - + ") LEFT JOIN " + Tables.CERTS + " ON (" - + Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " = " - + Tables.CERTS + "." + KeyRings.MASTER_KEY_ID - + " AND " + Tables.CERTS + "." + Certs.VERIFIED - + " = " + Certs.VERIFIED_SECRET - + ")" - ); - qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0"); - // in case there are multiple verifying certificates - groupBy = Tables.KEYS + "." + Keys.MASTER_KEY_ID; - - 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 '*', 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; - } - } - - if (TextUtils.isEmpty(sortOrder)) { - sortOrder = - Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL ASC, " - + Tables.USER_IDS + "." + UserIds.USER_ID + " ASC"; - } - - // uri to watch is all /key_rings/ - uri = KeyRings.CONTENT_URI; - - break; - } - - case KEY_RING_KEYS: { - HashMap projectionMap = new HashMap(); - 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); - - qb.setTables(Tables.KEYS); - qb.appendWhere(Keys.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - - break; - } - - case KEY_RING_USER_IDS: { - HashMap projectionMap = new HashMap(); - projectionMap.put(UserIds._ID, Tables.USER_IDS + ".oid AS _id"); - projectionMap.put(UserIds.MASTER_KEY_ID, Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID); - projectionMap.put(UserIds.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID); - projectionMap.put(UserIds.RANK, Tables.USER_IDS + "." + UserIds.RANK); - projectionMap.put(UserIds.IS_PRIMARY, Tables.USER_IDS + "." + UserIds.IS_PRIMARY); - projectionMap.put(UserIds.IS_REVOKED, Tables.USER_IDS + "." + UserIds.IS_REVOKED); - // we take the minimum (>0) here, where "1" is "verified by known secret key" - projectionMap.put(UserIds.VERIFIED, "MIN(" + Certs.VERIFIED + ") AS " + UserIds.VERIFIED); - qb.setProjectionMap(projectionMap); - - qb.setTables(Tables.USER_IDS - + " LEFT JOIN " + Tables.CERTS + " ON (" - + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " = " - + Tables.CERTS + "." + Certs.MASTER_KEY_ID - + " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = " - + Tables.CERTS + "." + Certs.RANK - + " AND " + Tables.CERTS + "." + Certs.VERIFIED + " > 0" - + ")"); - groupBy = Tables.USER_IDS + "." + UserIds.RANK; - - qb.appendWhere(Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - - if (TextUtils.isEmpty(sortOrder)) { - sortOrder = Tables.USER_IDS + "." + UserIds.RANK + " ASC"; - } - - break; - - } - - case KEY_RINGS_PUBLIC: - case KEY_RING_PUBLIC: { - HashMap projectionMap = new HashMap(); - 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.setTables(Tables.KEY_RINGS_PUBLIC); - - if(match == KEY_RING_PUBLIC) { - qb.appendWhere(KeyRings.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - } - - break; - } - - case KEY_RINGS_SECRET: - case KEY_RING_SECRET: { - HashMap projectionMap = new HashMap(); - 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); - - qb.setTables(Tables.KEY_RINGS_SECRET); - - if(match == KEY_RING_SECRET) { - qb.appendWhere(KeyRings.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - } - - break; - } - - case KEY_RING_CERTS: - case KEY_RING_CERTS_SPECIFIC: { - HashMap projectionMap = new HashMap(); - 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.VERIFIED, Tables.CERTS + "." + Certs.VERIFIED); - projectionMap.put(Certs.TYPE, Tables.CERTS + "." + Certs.TYPE); - projectionMap.put(Certs.CREATION, Tables.CERTS + "." + Certs.CREATION); - projectionMap.put(Certs.KEY_ID_CERTIFIER, Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER); - projectionMap.put(Certs.DATA, Tables.CERTS + "." + Certs.DATA); - projectionMap.put(Certs.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID); - projectionMap.put(Certs.SIGNER_UID, "signer." + UserIds.USER_ID + " AS " + Certs.SIGNER_UID); - qb.setProjectionMap(projectionMap); - - qb.setTables(Tables.CERTS - + " JOIN " + Tables.USER_IDS + " ON (" - + Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = " - + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID - + " AND " - + Tables.CERTS + "." + Certs.RANK + " = " - + Tables.USER_IDS + "." + UserIds.RANK - + ") LEFT JOIN " + Tables.USER_IDS + " AS signer ON (" - + Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER + " = " - + "signer." + UserIds.MASTER_KEY_ID - + " AND " - + "signer." + Keys.RANK + " = 0" - + ")"); - - groupBy = Tables.CERTS + "." + Certs.RANK + ", " - + Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER; - - qb.appendWhere(Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - if(match == KEY_RING_CERTS_SPECIFIC) { - qb.appendWhere(" AND " + Tables.CERTS + "." + Certs.RANK + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(3)); - qb.appendWhere(" AND " + Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER+ " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(4)); - } - - break; - } - - case API_APPS: - qb.setTables(Tables.API_APPS); - - break; - case API_APPS_BY_PACKAGE_NAME: - qb.setTables(Tables.API_APPS); - qb.appendWhere(ApiApps.PACKAGE_NAME + " = "); - qb.appendWhereEscapeString(uri.getLastPathSegment()); - - break; - 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 + " (" + match + ")"); - - } - - // If no sort order is specified use the default - String orderBy; - if (TextUtils.isEmpty(sortOrder)) { - orderBy = null; - } else { - 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 - c.setNotificationUri(getContext().getContentResolver(), uri); - - if (Constants.DEBUG) { - Log.d(Constants.TAG, - "Query: " - + qb.buildQuery(projection, selection, selectionArgs, null, null, - orderBy, null)); - Log.d(Constants.TAG, "Cursor: " + DatabaseUtils.dumpCursorToString(c)); - } - - return c; - } - - /** - * {@inheritDoc} - */ - @Override - public Uri insert(Uri uri, ContentValues values) { - Log.d(Constants.TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")"); - - final SQLiteDatabase db = getDb().getWritableDatabase(); - - Uri rowUri = null; - Long keyId = null; - try { - final int match = mUriMatcher.match(uri); - - switch (match) { - case KEY_RING_PUBLIC: - db.insertOrThrow(Tables.KEY_RINGS_PUBLIC, null, values); - keyId = values.getAsLong(KeyRings.MASTER_KEY_ID); - break; - - 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 KEY_RING_USER_IDS: - db.insertOrThrow(Tables.USER_IDS, null, values); - keyId = values.getAsLong(UserIds.MASTER_KEY_ID); - break; - - case KEY_RING_CERTS: - // we replace here, keeping only the latest signature - // TODO this would be better handled in saveKeyRing directly! - db.replaceOrThrow(Tables.CERTS, null, values); - keyId = values.getAsLong(Certs.MASTER_KEY_ID); - break; - - case API_APPS: - db.insertOrThrow(Tables.API_APPS, null, values); - break; - - 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); - - Log.d(Constants.TAG, "provider packageName: " + packageName); - - db.insertOrThrow(Tables.API_ACCOUNTS, null, values); - // TODO: this is wrong: -// rowUri = ApiAccounts.buildIdUri(Long.toString(rowId)); - - 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?", e); - } - - return rowUri; - } - - /** - * {@inheritDoc} - */ - @Override - public int delete(Uri uri, String additionalSelection, String[] selectionArgs) { - Log.v(Constants.TAG, "delete(uri=" + uri + ")"); - - final SQLiteDatabase db = getDb().getWritableDatabase(); - - int count; - final int match = mUriMatcher.match(uri); - - switch (match) { - 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_PUBLIC, selection, selectionArgs); - uri = KeyRings.buildGenericKeyRingUri(uri.getPathSegments().get(1)); - break; - } - 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_PACKAGE_NAME: - count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, additionalSelection), - selectionArgs); - break; - case API_ACCOUNTS_BY_ACCOUNT_NAME: - count = db.delete(Tables.API_ACCOUNTS, buildDefaultApiAccountsSelection(uri, additionalSelection), - selectionArgs); - break; - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); - } - - // notify of changes in db - getContext().getContentResolver().notifyChange(uri, null); - - return count; - } - - /** - * {@inheritDoc} - */ - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - Log.v(Constants.TAG, "update(uri=" + uri + ", values=" + values.toString() + ")"); - - final SQLiteDatabase db = mKeychainDatabase.getWritableDatabase(); - - String defaultSelection = null; - int count = 0; - try { - final int match = mUriMatcher.match(uri); - switch (match) { - case API_APPS_BY_PACKAGE_NAME: - count = db.update(Tables.API_APPS, values, - 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); - } - - // notify of changes in db - getContext().getContentResolver().notifyChange(uri, null); - - } catch (SQLiteConstraintException e) { - Log.e(Constants.TAG, "Constraint exception on update! Entry already existing?"); - } - - return count; - } - - /** - * 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, String selection) { - String packageName = DatabaseUtils.sqlEscapeString(uri.getLastPathSegment()); - - String andSelection = ""; - if (!TextUtils.isEmpty(selection)) { - andSelection = " AND (" + selection + ")"; - } - - return ApiApps.PACKAGE_NAME + "=" + packageName + andSelection; - } - - 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 + ")"; - } - - return ApiAccounts.PACKAGE_NAME + "=" + packageName + " AND " - + ApiAccounts.ACCOUNT_NAME + "=" + accountName - + andSelection; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java deleted file mode 100644 index 701ffc6af..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sufficientlysecure.keychain.provider; - -import android.net.Uri; -import android.provider.BaseColumns; -import org.sufficientlysecure.keychain.Constants; - -public class KeychainServiceBlobContract { - - interface BlobsColumns { - String KEY = "key"; - } - - public static final String CONTENT_AUTHORITY = Constants.PACKAGE_NAME + ".blobs"; - - private static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY); - - public static class Blobs implements BlobsColumns, BaseColumns { - public static final Uri CONTENT_URI = BASE_CONTENT_URI; - } - - private KeychainServiceBlobContract() { - } -} 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 deleted file mode 100644 index bc7de0b37..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann - * Copyright (C) 2011 Markus Doits - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sufficientlysecure.keychain.provider; - -import android.content.Context; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.provider.BaseColumns; -import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.BlobsColumns; - -public class KeychainServiceBlobDatabase extends SQLiteOpenHelper { - private static final String DATABASE_NAME = "openkeychain_blob.db"; - private static final int DATABASE_VERSION = 2; - - public static final String TABLE = "data"; - - public KeychainServiceBlobDatabase(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + TABLE + " ( " + BaseColumns._ID - + " INTEGER PRIMARY KEY AUTOINCREMENT, " + BlobsColumns.KEY + " TEXT NOT NULL)"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - // no upgrade necessary yet - } -} 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 deleted file mode 100644 index aa30e845d..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann - * Copyright (C) 2011 Markus Doits - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sufficientlysecure.keychain.provider; - -import android.content.ContentProvider; -import android.content.ContentUris; -import android.content.ContentValues; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import android.provider.BaseColumns; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.Blobs; -import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.BlobsColumns; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.List; -import java.util.UUID; - -public class KeychainServiceBlobProvider extends ContentProvider { - private static final String STORE_PATH = Constants.Path.APP_DIR + "/KeychainBlobs"; - - private KeychainServiceBlobDatabase mBlobDatabase = null; - - public KeychainServiceBlobProvider() { - File dir = new File(STORE_PATH); - dir.mkdirs(); - } - - @Override - public boolean onCreate() { - mBlobDatabase = new KeychainServiceBlobDatabase(getContext()); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public Uri insert(Uri uri, ContentValues ignored) { - // ContentValues are actually ignored, because we want to store a blob with no more - // information but have to create an record with the password generated here first - ContentValues vals = new ContentValues(); - - // Insert a random key in the database. This has to provided by the caller when updating or - // getting the blob - String password = UUID.randomUUID().toString(); - vals.put(BlobsColumns.KEY, password); - - SQLiteDatabase db = mBlobDatabase.getWritableDatabase(); - long newRowId = db.insert(KeychainServiceBlobDatabase.TABLE, null, vals); - Uri insertedUri = ContentUris.withAppendedId(Blobs.CONTENT_URI, newRowId); - - return Uri.withAppendedPath(insertedUri, password); - } - - /** - * {@inheritDoc} - */ - @Override - public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException, - FileNotFoundException { - Log.d(Constants.TAG, "openFile() called with uri: " + uri.toString() + " and mode: " + mode); - - List segments = uri.getPathSegments(); - if (segments.size() < 2) { - throw new SecurityException("Password not found in URI"); - } - String id = segments.get(0); - String key = segments.get(1); - - Log.d(Constants.TAG, "Got id: " + id + " and key: " + key); - - // get the data - SQLiteDatabase db = mBlobDatabase.getReadableDatabase(); - Cursor result = db.query(KeychainServiceBlobDatabase.TABLE, new String[]{BaseColumns._ID}, - BaseColumns._ID + " = ? and " + BlobsColumns.KEY + " = ?", - new String[]{id, key}, null, null, null); - - if (result.getCount() == 0) { - // either the key is wrong or no id exists - throw new FileNotFoundException("No file found with that ID and/or password"); - } - - File targetFile = new File(STORE_PATH, id); - if (mode.equals("w")) { - Log.d(Constants.TAG, "Try to open file w"); - if (!targetFile.exists()) { - try { - targetFile.createNewFile(); - } catch (IOException e) { - Log.e(Constants.TAG, "Got IEOException on creating new file", e); - throw new FileNotFoundException("Could not create file to write to"); - } - } - return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_WRITE_ONLY - | ParcelFileDescriptor.MODE_TRUNCATE); - } else if (mode.equals("r")) { - Log.d(Constants.TAG, "Try to open file r"); - if (!targetFile.exists()) { - throw new FileNotFoundException("Error: Could not find the file requested"); - } - return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY); - } - - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public String getType(Uri uri) { - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - /** - * {@inheritDoc} - */ - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } - -} 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 deleted file mode 100644 index 5e6d37237..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ /dev/null @@ -1,673 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.sufficientlysecure.keychain.provider; - -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.PGPException; -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.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; -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.Certs; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.remote.AccountSettings; -import org.sufficientlysecure.keychain.remote.AppSettings; -import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.security.SignatureException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class ProviderHelper { - - // 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 getGenericData(Context context, Uri uri, String[] proj, int[] types) { - Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null); - - HashMap result = new HashMap(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 getUnifiedData(Context context, long masterKeyId, String[] proj, int[] types) { - return getGenericData(context, KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)), proj, types); - } - - /** - * Find the master key id related to a given query. The id will either be extracted from the - * query, which should work for all specific /key_rings/ queries, or will be queried if it can't. - */ - public static long getMasterKeyId(Context context, Uri queryUri) { - // 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 getPGPKeyRings(Context context, Uri queryUri) { - Cursor cursor = context.getContentResolver().query(queryUri, - new String[]{KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA }, - null, null, null); - - Map result = new HashMap(cursor.getCount()); - if (cursor != null && cursor.moveToFirst()) do { - long masterKeyId = cursor.getLong(0); - byte[] data = cursor.getBlob(1); - if (data != null) { - result.put(masterKeyId, PgpConversionHelper.BytesToPGPKeyRing(data)); - } - } while(cursor.moveToNext()); - - if (cursor != null) { - cursor.close(); - } - - return result; - } - public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) { - Map result = getPGPKeyRings(context, queryUri); - if(result.isEmpty()) - return null; - return result.values().iterator().next(); - } - - 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 getPGPPublicKeyRing(Context context, - long masterKeyId) { - Uri queryUri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)); - return (PGPPublicKeyRing) getPGPKeyRing(context, queryUri); - } - - /** - * Retrieves the actual PGPSecretKeyRing object from the database blob based on the maserKeyId - */ - public static PGPSecretKeyRing getPGPSecretKeyRing(Context context, - long masterKeyId) { - Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)); - return (PGPSecretKeyRing) getPGPKeyRing(context, queryUri); - } - - /** - * Saves PGPPublicKeyRing with its keys and userIds in DB - */ - @SuppressWarnings("unchecked") - public static void saveKeyRing(Context context, PGPPublicKeyRing keyRing) throws IOException { - PGPPublicKey masterKey = keyRing.getPublicKey(); - long masterKeyId = masterKey.getKeyID(); - - // 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(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); - } - - 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 - values.put(KeyRingData.MASTER_KEY_ID, masterKeyId); - values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded()); - - // insert new version of this keyRing - Uri uri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)); - Uri insertedUri = context.getContentResolver().insert(uri, values); - - // save all keys and userIds included in keyRing object in database - ArrayList operations = new ArrayList(); - - int rank = 0; - for (PGPPublicKey key : new IterableIterator(keyRing.getPublicKeys())) { - operations.add(buildPublicKeyOperations(context, masterKeyId, key, rank)); - ++rank; - } - - // get a list of owned secret keys, for verification filtering - Map allKeyRings = getPGPKeyRings(context, KeyRingData.buildSecretKeyRingUri()); - // special case: available secret keys verify themselves! - if(secretRing != null) - allKeyRings.put(secretRing.getSecretKey().getKeyID(), secretRing); - - // classify and order user ids. primary are moved to the front, revoked to the back, - // otherwise the order in the keyfile is preserved. - List uids = new ArrayList(); - - for (String userId : new IterableIterator(masterKey.getUserIDs())) { - UserIdItem item = new UserIdItem(); - uids.add(item); - item.userId = userId; - - // look through signatures for this specific key - for (PGPSignature cert : new IterableIterator( - masterKey.getSignaturesForID(userId))) { - long certId = cert.getKeyID(); - try { - // self signature - if(certId == masterKeyId) { - cert.init(new JcaPGPContentVerifierBuilderProvider().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME), masterKey); - if(!cert.verifyCertification(userId, masterKey)) { - // not verified?! dang! TODO notify user? this is kinda serious... - Log.e(Constants.TAG, "Could not verify self signature for " + userId + "!"); - continue; - } - // is this the first, or a more recent certificate? - if(item.selfCert == null || - item.selfCert.getCreationTime().before(cert.getCreationTime())) { - item.selfCert = cert; - item.isPrimary = cert.getHashedSubPackets().isPrimaryUserID(); - item.isRevoked = - cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION; - } - } - // verify signatures from known private keys - if(allKeyRings.containsKey(certId)) { - // mark them as verified - cert.init(new JcaPGPContentVerifierBuilderProvider().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME), - allKeyRings.get(certId).getPublicKey()); - if(cert.verifyCertification(userId, masterKey)) { - item.trustedCerts.add(cert); - } - } - } catch(SignatureException e) { - Log.e(Constants.TAG, "Signature verification failed! " - + PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID()) - + " from " - + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e); - } catch(PGPException e) { - Log.e(Constants.TAG, "Signature verification failed! " - + PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID()) - + " from " - + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e); - } - } - } - - // primary before regular before revoked (see UserIdItem.compareTo) - // this is a stable sort, so the order of keys is otherwise preserved. - Collections.sort(uids); - // iterate and put into db - for(int userIdRank = 0; userIdRank < uids.size(); userIdRank++) { - UserIdItem item = uids.get(userIdRank); - operations.add(buildUserIdOperations(masterKeyId, item, userIdRank)); - // no self cert is bad, but allowed by the rfc... - if(item.selfCert != null) { - operations.add(buildCertOperations( - masterKeyId, userIdRank, item.selfCert, Certs.VERIFIED_SELF)); - } - // don't bother with trusted certs if the uid is revoked, anyways - if(item.isRevoked) { - continue; - } - for(int i = 0; i < item.trustedCerts.size(); i++) { - operations.add(buildCertOperations( - masterKeyId, userIdRank, item.trustedCerts.get(i), Certs.VERIFIED_SECRET)); - } - } - - 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 the saved keyring (if any) - if(secretRing != null) { - saveKeyRing(context, secretRing); - } - - } - - private static class UserIdItem implements Comparable { - String userId; - boolean isPrimary = false; - boolean isRevoked = false; - PGPSignature selfCert; - List trustedCerts = new ArrayList(); - - @Override - public int compareTo(UserIdItem o) { - // if one key is primary but the other isn't, the primary one always comes first - if(isPrimary != o.isPrimary) - return isPrimary ? -1 : 1; - // revoked keys always come last! - if(isRevoked != o.isRevoked) - return isRevoked ? 1 : -1; - return 0; - } - } - - /** - * 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 { - long masterKeyId = keyRing.getPublicKey().getKeyID(); - - // save secret keyring - ContentValues values = new ContentValues(); - values.put(KeyRingData.MASTER_KEY_ID, masterKeyId); - values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded()); - // insert new version of this keyRing - Uri uri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)); - context.getContentResolver().insert(uri, values); - - } - - /** - * Saves (or updates) a pair of public and secret KeyRings in the database - */ - @SuppressWarnings("unchecked") - public static void saveKeyRing(Context context, PGPPublicKeyRing pubRing, PGPSecretKeyRing privRing) throws IOException { - long masterKeyId = pubRing.getPublicKey().getKeyID(); - - // delete secret keyring (so it isn't unnecessarily saved by public-saveKeyRing below) - context.getContentResolver().delete(KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null); - - // save public keyring - saveKeyRing(context, pubRing); - saveKeyRing(context, privRing); - } - - /** - * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing - */ - private static ContentProviderOperation buildPublicKeyOperations(Context context, - 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.KEY_SIZE, key.getBitStrength()); - 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); - } - - Uri uri = Keys.buildKeysUri(Long.toString(masterKeyId)); - - return ContentProviderOperation.newInsert(uri).withValues(values).build(); - } - - /** - * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing - */ - private static ContentProviderOperation buildCertOperations(long masterKeyId, - int rank, - PGPSignature cert, - int verified) - throws IOException { - ContentValues values = new ContentValues(); - values.put(Certs.MASTER_KEY_ID, masterKeyId); - values.put(Certs.RANK, rank); - values.put(Certs.KEY_ID_CERTIFIER, cert.getKeyID()); - values.put(Certs.TYPE, cert.getSignatureType()); - values.put(Certs.CREATION, cert.getCreationTime().getTime() / 1000); - values.put(Certs.VERIFIED, verified); - values.put(Certs.DATA, cert.getEncoded()); - - Uri uri = Certs.buildCertsUri(Long.toString(masterKeyId)); - - return ContentProviderOperation.newInsert(uri).withValues(values).build(); - } - - /** - * Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing - */ - private static ContentProviderOperation buildUserIdOperations(long masterKeyId, UserIdItem item, - int rank) { - ContentValues values = new ContentValues(); - values.put(UserIds.MASTER_KEY_ID, masterKeyId); - values.put(UserIds.USER_ID, item.userId); - values.put(UserIds.IS_PRIMARY, item.isPrimary); - values.put(UserIds.IS_REVOKED, item.isRevoked); - values.put(UserIds.RANK, rank); - - Uri uri = UserIds.buildUserIdsUri(Long.toString(masterKeyId)); - - return ContentProviderOperation.newInsert(uri).withValues(values).build(); - } - - public static ArrayList getKeyRingsAsArmoredString(Context context, long[] masterKeyIds) { - ArrayList output = new ArrayList(); - - if (masterKeyIds != null && masterKeyIds.length > 0) { - - Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, masterKeyIds); - - if (cursor != null) { - 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)); - - // get actual keyring data blob and write it to ByteArrayOutputStream - try { - Object keyRing = null; - byte[] data = cursor.getBlob(dataCol); - if (data != null) { - keyRing = PgpConversionHelper.BytesToPGPKeyRing(data); - } - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ArmoredOutputStream aos = new ArmoredOutputStream(bos); - aos.setHeader("Version", PgpHelper.getFullVersion(context)); - - if (keyRing instanceof PGPSecretKeyRing) { - aos.write(((PGPSecretKeyRing) keyRing).getEncoded()); - } else if (keyRing instanceof PGPPublicKeyRing) { - aos.write(((PGPPublicKeyRing) keyRing).getEncoded()); - } - aos.close(); - - String armoredKey = bos.toString("UTF-8"); - - Log.d(Constants.TAG, "armoredKey:" + armoredKey); - - output.add(armoredKey); - } 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!"); - } - - if (output.size() > 0) { - return output; - } else { - return null; - } - } - - private static Cursor getCursorWithSelectedKeyringMasterKeyIds(Context context, long[] masterKeyIds) { - Cursor cursor = null; - if (masterKeyIds != null && masterKeyIds.length > 0) { - - String inMasterKeyList = KeyRingData.MASTER_KEY_ID + " IN ("; - for (int i = 0; i < masterKeyIds.length; ++i) { - if (i != 0) { - inMasterKeyList += ", "; - } - inMasterKeyList += DatabaseUtils.sqlEscapeString("" + masterKeyIds[i]); - } - inMasterKeyList += ")"; - - cursor = context.getContentResolver().query(KeyRingData.buildPublicKeyRingUri(), new String[] { - KeyRingData._ID, KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA - }, inMasterKeyList, null, null); - } - - return cursor; - } - - public static ArrayList getRegisteredApiApps(Context context) { - Cursor cursor = context.getContentResolver().query(ApiApps.CONTENT_URI, null, null, null, - null); - - ArrayList packageNames = new ArrayList(); - if (cursor != null) { - int packageNameCol = cursor.getColumnIndex(ApiApps.PACKAGE_NAME); - if (cursor.moveToFirst()) { - do { - packageNames.add(cursor.getString(packageNameCol)); - } while (cursor.moveToNext()); - } - } - - if (cursor != null) { - cursor.close(); - } - - return packageNames; - } - - private static ContentValues contentValueForApiApps(AppSettings appSettings) { - ContentValues values = new ContentValues(); - values.put(ApiApps.PACKAGE_NAME, appSettings.getPackageName()); - values.put(ApiApps.PACKAGE_SIGNATURE, appSettings.getPackageSignature()); - 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(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) { - throw new RuntimeException(); - } - } - - 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))); - } - - 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 getAllKeyIdsForApp(Context context, Uri uri) { - Set keyIds = new HashSet(); - - 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 = ApiApps.buildByPackageNameUri(packageName); - - String[] projection = new String[]{ApiApps.PACKAGE_SIGNATURE}; - - ContentResolver cr = context.getContentResolver(); - Cursor cursor = cr.query(queryUri, projection, null, null, null); - - byte[] signature = null; - if (cursor != null && cursor.moveToFirst()) { - int signatureCol = 0; - - signature = cursor.getBlob(signatureCol); - } - - if (cursor != null) { - cursor.close(); - } - - return signature; - } -} -- cgit v1.2.3