diff options
Diffstat (limited to 'org_apg/src/org/thialfihar/android/apg/provider')
9 files changed, 1046 insertions, 1113 deletions
diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ApgContract.java b/org_apg/src/org/thialfihar/android/apg/provider/ApgContract.java new file mode 100644 index 000000000..10f9fa05e --- /dev/null +++ b/org_apg/src/org/thialfihar/android/apg/provider/ApgContract.java @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + * + * 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.thialfihar.android.apg.provider; + +import android.net.Uri; +import android.provider.BaseColumns; + +/** + * TODO: + * + * Breaking compatibility?: + * + * - change CONTENT_AUTHORITY + * + * - change type names + * + */ +public class ApgContract { + + interface KeyRingsColumns { + String MASTER_KEY_ID = "master_key_id"; // TODO: clarify + String TYPE = "type"; // see KeyTypes + String WHO_ID = "who_id"; + String KEY_RING_DATA = "key_ring_data"; // blob + } + + interface KeysColumns { + String KEY_ID = "key_id"; // not a database id + String TYPE = "type"; // see KeyTypes + String IS_MASTER_KEY = "is_master_key"; + String ALGORITHM = "algorithm"; + String KEY_SIZE = "key_size"; + String CAN_SIGN = "can_sign"; + String CAN_ENCRYPT = "can_encrypt"; + String IS_REVOKED = "is_revoked"; + String CREATION = "creation"; + String EXPIRY = "expiry"; + String KEY_RING_ROW_ID = "key_ring_id"; // foreign key to key_rings._ID + String KEY_DATA = "key_data"; + String RANK = "key_data"; // blob + } + + interface UserIdsColumns { + String KEY_ROW_ID = "key_id"; // foreign key to keys._ID + String USER_ID = "user_id"; // not a database id + String RANK = "rank"; + } + + public static final class KeyTypes { + public static final int PUBLIC = 0; + public static final int SECRET = 1; + } + + public static final String CONTENT_AUTHORITY = "org.thialfihar.android.apg.provider"; + // public static final String CONTENT_AUTHORITY = Constants.PACKAGE_NAME; + + private static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY); + + public static final String BASE_KEY_RINGS = "key_rings"; + public static final String BASE_DATA = "data"; + + public static final String PATH_PUBLIC = "public"; + public static final String PATH_SECRET = "secret"; + + public static final String PATH_BY_KEY_ID = "key_id"; + public static final String PATH_BY_EMAILS = "emails"; + + public static final String PATH_RANK = "#"; + + public static final String PATH_USER_IDS = "user_ids"; + public static final String PATH_KEYS = "keys"; + + public static class PublicKeyRings implements KeyRingsColumns, BaseColumns { + public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() + .appendPath(BASE_KEY_RINGS).appendPath(PATH_PUBLIC).build(); + + /** Use if multiple items get returned */ + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.public.key_ring"; + + /** Use if a single item is returned */ + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.public.key_ring"; + + public static Uri buildPublicKeyRingsUri() { + return CONTENT_URI.buildUpon().build(); + } + + public static Uri buildPublicKeyRingsUri(String keyRingRowId) { + return CONTENT_URI.buildUpon().appendPath(keyRingRowId).build(); + } + + public static Uri buildPublicKeyRingsByKeyIdUri(String keyRowId) { + return CONTENT_URI.buildUpon().appendPath(PATH_BY_KEY_ID).appendPath(keyRowId).build(); + } + + public static Uri buildPublicKeyRingsByEmailsUri(String emails) { + return CONTENT_URI.buildUpon().appendPath(PATH_BY_EMAILS).appendPath(emails).build(); + } + } + + public static class SecretKeyRings implements KeyRingsColumns, BaseColumns { + public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() + .appendPath(BASE_KEY_RINGS).appendPath(PATH_SECRET).build(); + + /** Use if multiple items get returned */ + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.secret.key_ring"; + + /** Use if a single item is returned */ + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.secret.key_ring"; + + public static Uri buildSecretKeyRingsUri() { + return CONTENT_URI.buildUpon().build(); + } + + public static Uri buildSecretKeyRingsUri(String keyRingRowId) { + return CONTENT_URI.buildUpon().appendPath(keyRingRowId).build(); + } + + public static Uri buildSecretKeyRingsByKeyIdUri(String keyRowId) { + return CONTENT_URI.buildUpon().appendPath(PATH_BY_KEY_ID).appendPath(keyRowId).build(); + } + + public static Uri buildSecretKeyRingsByEmailsUri(String emails) { + return CONTENT_URI.buildUpon().appendPath(PATH_BY_EMAILS).appendPath(emails).build(); + } + } + + public static class PublicKeys implements KeysColumns, BaseColumns { + public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() + .appendPath(BASE_KEY_RINGS).appendPath(PATH_PUBLIC).build(); + + /** Use if multiple items get returned */ + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.public.key"; + + /** Use if a single item is returned */ + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.public.key"; + + public static Uri buildPublicKeysUri(String keyRingRowId) { + return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_KEYS).build(); + } + + public static Uri buildPublicKeysRankUri(String keyRingRowId) { + return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_KEYS) + .appendPath(PATH_RANK).build(); + } + } + + public static class SecretKeys implements KeysColumns, BaseColumns { + public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() + .appendPath(BASE_KEY_RINGS).appendPath(PATH_SECRET).build(); + + /** Use if multiple items get returned */ + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.secret.key"; + + /** Use if a single item is returned */ + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.secret.key"; + + public static Uri buildSecretKeysUri(String keyRingRowId) { + return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_KEYS).build(); + } + + public static Uri buildSecretKeysRankUri(String keyRingRowId) { + return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_KEYS) + .appendPath(PATH_RANK).build(); + } + } + + public static class PublicUserIds implements UserIdsColumns, BaseColumns { + public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() + .appendPath(BASE_KEY_RINGS).appendPath(PATH_PUBLIC).build(); + + /** Use if multiple items get returned */ + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.user_id"; + + /** Use if a single item is returned */ + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.user_id"; + + public static Uri buildPublicUserIdsUri(String keyRingRowId) { + return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_USER_IDS) + .build(); + } + + public static Uri buildPublicUserIdsRankUri(String keyRingRowId) { + return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_USER_IDS) + .appendPath(PATH_RANK).build(); + } + } + + public static class SecretUserIds implements UserIdsColumns, BaseColumns { + public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() + .appendPath(BASE_KEY_RINGS).appendPath(PATH_SECRET).build(); + + /** Use if multiple items get returned */ + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.user_id"; + + /** Use if a single item is returned */ + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.user_id"; + + public static Uri buildSecretUserIdsUri(String keyRingRowId) { + return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_USER_IDS) + .build(); + } + + public static Uri buildSecretUserIdsRankUri(String keyRingRowId) { + return CONTENT_URI.buildUpon().appendPath(keyRingRowId).appendPath(PATH_USER_IDS) + .appendPath(PATH_RANK).build(); + } + } + + public static class DataStream { + public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(BASE_DATA) + .build(); + + public static Uri buildDataStreamUri(String streamFilename) { + return CONTENT_URI.buildUpon().appendPath(streamFilename).build(); + } + } + + private ApgContract() { + } +} diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ApgDatabase.java b/org_apg/src/org/thialfihar/android/apg/provider/ApgDatabase.java new file mode 100644 index 000000000..fdee2f101 --- /dev/null +++ b/org_apg/src/org/thialfihar/android/apg/provider/ApgDatabase.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + * + * 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.thialfihar.android.apg.provider; + +import org.thialfihar.android.apg.Constants; +import org.thialfihar.android.apg.provider.ApgContract.KeyRingsColumns; +import org.thialfihar.android.apg.provider.ApgContract.KeysColumns; +import org.thialfihar.android.apg.provider.ApgContract.UserIdsColumns; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.provider.BaseColumns; + +import org.thialfihar.android.apg.util.Log; + +public class ApgDatabase extends SQLiteOpenHelper { + private static final String DATABASE_NAME = "apg.db"; + // Last APG 1 db version was 2 + private static final int DATABASE_VERSION = 3; + + public interface Tables { + String KEY_RINGS = "key_rings"; + String KEYS = "keys"; + String USER_IDS = "user_ids"; + } + + private static final String CREATE_KEY_RINGS = "CREATE TABLE IF NOT EXISTS " + Tables.KEY_RINGS + + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY, " + KeyRingsColumns.MASTER_KEY_ID + + " INT64, " + KeyRingsColumns.TYPE + " INTEGER, " + KeyRingsColumns.WHO_ID + + " INTEGER, " + KeyRingsColumns.KEY_RING_DATA + " BLOB)"; + + private static final String CREATE_KEYS = "CREATE TABLE IF NOT EXISTS " + Tables.KEYS + " (" + + BaseColumns._ID + " INTEGER PRIMARY KEY, " + KeysColumns.KEY_ID + " INT64, " + + KeysColumns.TYPE + " INTEGER, " + KeysColumns.IS_MASTER_KEY + " INTEGER, " + + KeysColumns.ALGORITHM + " INTEGER, " + KeysColumns.KEY_SIZE + " INTEGER, " + + KeysColumns.CAN_SIGN + " INTEGER, " + KeysColumns.CAN_ENCRYPT + " INTEGER, " + + KeysColumns.IS_REVOKED + " INTEGER, " + KeysColumns.CREATION + " INTEGER, " + + KeysColumns.EXPIRY + " INTEGER, " + KeysColumns.KEY_RING_ROW_ID + + " INTEGER REFERENCES " + Tables.KEY_RINGS + " ON DELETE CASCADE, " + + KeysColumns.KEY_DATA + " BLOB," + KeysColumns.RANK + " INTEGER)"; + + private static final String CREATE_USER_IDS = "CREATE TABLE IF NOT EXISTS " + Tables.USER_IDS + + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY, " + UserIdsColumns.KEY_ROW_ID + + " INTEGER REFERENCES " + Tables.KEYS + " ON DELETE CASCADE, " + + UserIdsColumns.USER_ID + " TEXT, " + UserIdsColumns.RANK + " INTEGER)"; + + ApgDatabase(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + // + // public static HashMap<String, String> sKeyRingsProjection; + // public static HashMap<String, String> sKeysProjection; + // public static HashMap<String, String> sUserIdsProjection; + // + // private SQLiteDatabase mDb = null; + // private int mStatus = 0; + // + // static { + // sKeyRingsProjection = new HashMap<String, String>(); + // sKeyRingsProjection.put(KeyRings._ID, KeyRings._ID); + // sKeyRingsProjection.put(KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID); + // sKeyRingsProjection.put(KeyRings.TYPE, KeyRings.TYPE); + // sKeyRingsProjection.put(KeyRings.WHO_ID, KeyRings.WHO_ID); + // sKeyRingsProjection.put(KeyRings.KEY_RING_DATA, KeyRings.KEY_RING_DATA); + // + // sKeysProjection = new HashMap<String, String>(); + // sKeysProjection.put(Keys._ID, Keys._ID); + // sKeysProjection.put(Keys.KEY_ID, Keys.KEY_ID); + // sKeysProjection.put(Keys.TYPE, Keys.TYPE); + // sKeysProjection.put(Keys.IS_MASTER_KEY, Keys.IS_MASTER_KEY); + // sKeysProjection.put(Keys.ALGORITHM, Keys.ALGORITHM); + // sKeysProjection.put(Keys.KEY_SIZE, Keys.KEY_SIZE); + // sKeysProjection.put(Keys.CAN_SIGN, Keys.CAN_SIGN); + // sKeysProjection.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT); + // sKeysProjection.put(Keys.IS_REVOKED, Keys.IS_REVOKED); + // sKeysProjection.put(Keys.CREATION, Keys.CREATION); + // sKeysProjection.put(Keys.EXPIRY, Keys.EXPIRY); + // sKeysProjection.put(Keys.KEY_DATA, Keys.KEY_DATA); + // sKeysProjection.put(Keys.RANK, Keys.RANK); + // + // sUserIdsProjection = new HashMap<String, String>(); + // sUserIdsProjection.put(UserIds._ID, UserIds._ID); + // sUserIdsProjection.put(UserIds.KEY_ID, UserIds.KEY_ID); + // sUserIdsProjection.put(UserIds.USER_ID, UserIds.USER_ID); + // sUserIdsProjection.put(UserIds.RANK, UserIds.RANK); + // } + + @Override + public void onCreate(SQLiteDatabase db) { + Log.w(Constants.TAG, "Creating database..."); + + db.execSQL(CREATE_KEY_RINGS); + db.execSQL(CREATE_KEYS); + db.execSQL(CREATE_USER_IDS); + } + + @Override + public void onOpen(SQLiteDatabase db) { + super.onOpen(db); + if (!db.isReadOnly()) { + // Enable foreign key constraints + db.execSQL("PRAGMA foreign_keys=ON;"); + } + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w(Constants.TAG, "Upgrading database from version " + oldVersion + " to " + newVersion); + + // Upgrade from oldVersion through all methods to newest one + for (int version = oldVersion; version < newVersion; ++version) { + Log.w(Constants.TAG, "Upgrading database to version " + version); + + switch (version) { + case 1: + + break; + + default: + break; + + } + } + } + +} diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ApgProvider.java b/org_apg/src/org/thialfihar/android/apg/provider/ApgProvider.java new file mode 100644 index 000000000..e25228434 --- /dev/null +++ b/org_apg/src/org/thialfihar/android/apg/provider/ApgProvider.java @@ -0,0 +1,589 @@ +/* + * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> + * + * 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.thialfihar.android.apg.provider; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Arrays; +import java.util.HashMap; + +import org.thialfihar.android.apg.Constants; +import org.thialfihar.android.apg.provider.ApgContract.KeyRingsColumns; +import org.thialfihar.android.apg.provider.ApgContract.KeyTypes; +import org.thialfihar.android.apg.provider.ApgContract.KeysColumns; +import org.thialfihar.android.apg.provider.ApgContract.PublicKeyRings; +import org.thialfihar.android.apg.provider.ApgContract.PublicKeys; +import org.thialfihar.android.apg.provider.ApgContract.PublicUserIds; +import org.thialfihar.android.apg.provider.ApgContract.SecretKeyRings; +import org.thialfihar.android.apg.provider.ApgContract.SecretKeys; +import org.thialfihar.android.apg.provider.ApgContract.SecretUserIds; +import org.thialfihar.android.apg.provider.ApgContract.UserIdsColumns; +import org.thialfihar.android.apg.provider.ApgDatabase.Tables; +import org.thialfihar.android.apg.util.Log; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.Context; +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.os.ParcelFileDescriptor; +import android.provider.BaseColumns; +import android.text.TextUtils; + +public class ApgProvider extends ContentProvider { + private static final UriMatcher sUriMatcher = buildUriMatcher(); + + private static final int PUBLIC_KEY_RING = 101; + private static final int PUBLIC_KEY_RING_ID = 102; + private static final int PUBLIC_KEY_RING_BY_KEY_ID = 103; + private static final int PUBLIC_KEY_RING_BY_EMAILS = 104; + private static final int PUBLIC_KEY_RING_KEY = 111; + private static final int PUBLIC_KEY_RING_KEY_RANK = 112; + private static final int PUBLIC_KEY_RING_USER_ID = 121; + private static final int PUBLIC_KEY_RING_USER_ID_RANK = 122; + + private static final int SECRET_KEY_RING = 201; + private static final int SECRET_KEY_RING_ID = 202; + private static final int SECRET_KEY_RING_BY_KEY_ID = 203; + private static final int SECRET_KEY_RING_BY_EMAILS = 204; + private static final int SECRET_KEY_RING_KEY = 211; + private static final int SECRET_KEY_RING_KEY_RANK = 212; + private static final int SECRET_KEY_RING_USER_ID = 221; + private static final int SECRET_KEY_RING_USER_ID_RANK = 222; + + private static final int DATA_STREAM = 301; + + /** + * Build and return a {@link UriMatcher} that catches all {@link Uri} variations supported by + * this {@link ContentProvider}. + */ + private static UriMatcher buildUriMatcher() { + final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); + final String authority = ApgContract.CONTENT_AUTHORITY; + + /** + * public key rings + * + * <pre> + * key_rings/public + * key_rings/public/_ + * key_rings/public/key_id/_ + * key_rings/public/emails/_ + * </pre> + */ + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC, + PUBLIC_KEY_RING); + matcher.addURI(authority, + ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + "/*", + PUBLIC_KEY_RING_ID); + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + "/" + + ApgContract.PATH_BY_KEY_ID + "/*", PUBLIC_KEY_RING_BY_KEY_ID); + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + "/" + + ApgContract.PATH_BY_EMAILS + "/*", PUBLIC_KEY_RING_BY_EMAILS); + + /** + * public keys + * + * <pre> + * key_rings/public/_/keys + * key_rings/public/_/keys/# + * </pre> + */ + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + + "/*/" + ApgContract.PATH_KEYS, PUBLIC_KEY_RING_KEY); + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + + "/*/" + ApgContract.PATH_KEYS + "/" + ApgContract.PATH_RANK, + PUBLIC_KEY_RING_KEY_RANK); + + /** + * public user ids + * + * <pre> + * key_rings/public/_/user_ids + * key_rings/public/_/user_ids/# + * </pre> + */ + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + + "/*/" + ApgContract.PATH_USER_IDS, PUBLIC_KEY_RING_USER_ID); + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_PUBLIC + + "/*/" + ApgContract.PATH_USER_IDS + "/" + ApgContract.PATH_RANK, + PUBLIC_KEY_RING_USER_ID_RANK); + + /** + * secret key rings + * + * <pre> + * key_rings/secret + * key_rings/secret/* + * key_rings/secret/key_id/* + * key_rings/secret/emails/* + * </pre> + */ + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET, + SECRET_KEY_RING); + matcher.addURI(authority, + ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + "/*", + SECRET_KEY_RING_ID); + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + "/" + + ApgContract.PATH_BY_KEY_ID + "/*", SECRET_KEY_RING_BY_KEY_ID); + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + "/" + + ApgContract.PATH_BY_EMAILS + "/*", SECRET_KEY_RING_BY_EMAILS); + + /** + * secret keys + * + * <pre> + * key_rings/secret/_/keys + * key_rings/secret/_/keys/# + * </pre> + */ + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + + "/*/" + ApgContract.PATH_KEYS, SECRET_KEY_RING_KEY); + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + + "/*/" + ApgContract.PATH_KEYS + "/" + ApgContract.PATH_RANK, + SECRET_KEY_RING_KEY_RANK); + + /** + * secret user ids + * + * <pre> + * key_rings/secret/_/user_ids + * key_rings/secret/_/user_ids/# + * </pre> + */ + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + + "/*/" + ApgContract.PATH_USER_IDS, SECRET_KEY_RING_USER_ID); + matcher.addURI(authority, ApgContract.BASE_KEY_RINGS + "/" + ApgContract.PATH_SECRET + + "/*/" + ApgContract.PATH_USER_IDS + "/" + ApgContract.PATH_RANK, + SECRET_KEY_RING_USER_ID_RANK); + + /** + * data stream + * + * <pre> + * data/* + * </pre> + */ + matcher.addURI(authority, ApgContract.BASE_DATA + "/*", DATA_STREAM); + + return matcher; + } + + private ApgDatabase mApgDatabase; + + /** {@inheritDoc} */ + @Override + public boolean onCreate() { + final Context context = getContext(); + mApgDatabase = new ApgDatabase(context); + return true; + } + + /** {@inheritDoc} */ + @Override + public String getType(Uri uri) { + final int match = sUriMatcher.match(uri); + switch (match) { + case PUBLIC_KEY_RING: + case PUBLIC_KEY_RING_BY_EMAILS: + return PublicKeyRings.CONTENT_TYPE; + + case PUBLIC_KEY_RING_ID: + case PUBLIC_KEY_RING_BY_KEY_ID: + return PublicKeyRings.CONTENT_ITEM_TYPE; + + case PUBLIC_KEY_RING_KEY: + return PublicKeys.CONTENT_TYPE; + + case PUBLIC_KEY_RING_KEY_RANK: + return PublicKeys.CONTENT_ITEM_TYPE; + + case PUBLIC_KEY_RING_USER_ID: + return PublicUserIds.CONTENT_TYPE; + + case PUBLIC_KEY_RING_USER_ID_RANK: + return PublicUserIds.CONTENT_ITEM_TYPE; + + case SECRET_KEY_RING: + case SECRET_KEY_RING_BY_EMAILS: + return SecretKeyRings.CONTENT_TYPE; + + case SECRET_KEY_RING_ID: + case SECRET_KEY_RING_BY_KEY_ID: + return SecretKeyRings.CONTENT_ITEM_TYPE; + + case SECRET_KEY_RING_KEY: + return SecretKeys.CONTENT_TYPE; + + case SECRET_KEY_RING_KEY_RANK: + return SecretKeys.CONTENT_ITEM_TYPE; + + case SECRET_KEY_RING_USER_ID: + return SecretUserIds.CONTENT_TYPE; + + case SECRET_KEY_RING_USER_ID_RANK: + return SecretUserIds.CONTENT_ITEM_TYPE; + + default: + throw new UnsupportedOperationException("Unknown uri: " + uri); + } + } + + /** + * Returns weather the key is a public or secret one + * + * @param uri + * @return + */ + private int getKeyType(int match) { + int type; + switch (match) { + case PUBLIC_KEY_RING: + case PUBLIC_KEY_RING_ID: + case PUBLIC_KEY_RING_BY_KEY_ID: + case PUBLIC_KEY_RING_BY_EMAILS: + case PUBLIC_KEY_RING_KEY: + case PUBLIC_KEY_RING_KEY_RANK: + case PUBLIC_KEY_RING_USER_ID: + case PUBLIC_KEY_RING_USER_ID_RANK: + type = KeyTypes.PUBLIC; + break; + + case SECRET_KEY_RING: + case SECRET_KEY_RING_ID: + case SECRET_KEY_RING_BY_KEY_ID: + case SECRET_KEY_RING_BY_EMAILS: + case SECRET_KEY_RING_KEY: + case SECRET_KEY_RING_KEY_RANK: + case SECRET_KEY_RING_USER_ID: + case SECRET_KEY_RING_USER_ID_RANK: + type = KeyTypes.SECRET; + break; + + default: + throw new IllegalArgumentException("Unknown match " + match); + + } + + return type; + } + + /** {@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(); + SQLiteDatabase db = mApgDatabase.getReadableDatabase(); + + HashMap<String, String> projectionMap = new HashMap<String, String>(); + + int match = sUriMatcher.match(uri); + + qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = " + getKeyType(match)); + + switch (match) { + case PUBLIC_KEY_RING_ID: + case SECRET_KEY_RING_ID: + qb.appendWhere(" AND " + Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID + " = "); + qb.appendWhereEscapeString(uri.getPathSegments().get(2)); + + // break omitted intentionally + + case PUBLIC_KEY_RING: + case SECRET_KEY_RING: + qb.setTables(Tables.KEY_RINGS + " INNER JOIN " + Tables.KEYS + " ON " + "(" + + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.KEYS + "." + + KeysColumns.KEY_RING_ID + " AND " + Tables.KEYS + "." + + KeysColumns.IS_MASTER_KEY + " = '1'" + ") " + " INNER JOIN " + + Tables.USER_IDS + " ON " + "(" + Tables.KEYS + "." + BaseColumns._ID + " = " + + Tables.USER_IDS + "." + UserIdsColumns.KEY_ID + " AND " + Tables.USER_IDS + + "." + UserIdsColumns.RANK + " = '0') "); + + projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID); + projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." + + KeyRingsColumns.MASTER_KEY_ID); + projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + + UserIdsColumns.USER_ID); + + if (TextUtils.isEmpty(sortOrder)) { + sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC"; + } + + break; + + case SECRET_KEY_RING_BY_KEY_ID: + case PUBLIC_KEY_RING_BY_KEY_ID: + qb.setTables(Tables.KEYS + " AS tmp INNER JOIN " + Tables.KEY_RINGS + " ON (" + + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + "tmp." + + KeysColumns.KEY_RING_ID + ")" + " INNER JOIN " + Tables.KEYS + " ON " + "(" + + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.KEYS + "." + + KeysColumns.KEY_RING_ID + " AND " + Tables.KEYS + "." + + KeysColumns.IS_MASTER_KEY + " = '1'" + ") " + " INNER JOIN " + + Tables.USER_IDS + " ON " + "(" + Tables.KEYS + "." + BaseColumns._ID + " = " + + Tables.USER_IDS + "." + UserIdsColumns.KEY_ID + " AND " + Tables.USER_IDS + + "." + UserIdsColumns.RANK + " = '0') "); + + projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID); + projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." + + KeyRingsColumns.MASTER_KEY_ID); + projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + + UserIdsColumns.USER_ID); + + qb.appendWhere(" AND tmp." + KeysColumns.KEY_ID + " = "); + qb.appendWhereEscapeString(uri.getPathSegments().get(3)); + + break; + + case SECRET_KEY_RING_BY_EMAILS: + case PUBLIC_KEY_RING_BY_EMAILS: + qb.setTables(Tables.KEY_RINGS + " INNER JOIN " + Tables.KEYS + " ON " + "(" + + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.KEYS + "." + + KeysColumns.KEY_RING_ID + " AND " + Tables.KEYS + "." + + KeysColumns.IS_MASTER_KEY + " = '1'" + ") " + " INNER JOIN " + + Tables.USER_IDS + " ON " + "(" + Tables.KEYS + "." + BaseColumns._ID + " = " + + Tables.USER_IDS + "." + UserIdsColumns.KEY_ID + " AND " + Tables.USER_IDS + + "." + UserIdsColumns.RANK + " = '0') "); + + projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID); + projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." + + KeyRingsColumns.MASTER_KEY_ID); + projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + + UserIdsColumns.USER_ID); + + String emails = uri.getPathSegments().get(3); + String chunks[] = emails.split(" *, *"); + boolean gotCondition = false; + String emailWhere = ""; + for (int i = 0; i < chunks.length; ++i) { + if (chunks[i].length() == 0) { + continue; + } + if (i != 0) { + emailWhere += " OR "; + } + emailWhere += "tmp." + UserIdsColumns.USER_ID + " LIKE "; + // match '*<email>', so it has to be at the *end* of the user id + emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">"); + gotCondition = true; + } + + if (gotCondition) { + qb.appendWhere(" AND EXISTS (SELECT tmp." + BaseColumns._ID + " FROM " + + Tables.USER_IDS + " AS tmp WHERE tmp." + UserIdsColumns.KEY_ID + " = " + + Tables.KEYS + "." + BaseColumns._ID + " AND (" + emailWhere + "))"); + } + + break; + + default: + throw new IllegalArgumentException("Unknown URI " + uri); + + } + + qb.setProjectionMap(projectionMap); + + // If no sort order is specified use the default + String orderBy; + if (TextUtils.isEmpty(sortOrder)) { + orderBy = null; + } else { + orderBy = sortOrder; + } + + Log.d(Constants.TAG, + qb.buildQuery(projection, selection, selectionArgs, null, null, orderBy, null) + .replace("WHERE", "WHERE\n")); + Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy); + + // Tell the cursor what uri to watch, so it knows when its source data changes + c.setNotificationUri(getContext().getContentResolver(), uri); + return c; + } + + /** {@inheritDoc} */ + @Override + public Uri insert(Uri uri, ContentValues values) { + Log.d(Constants.TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")"); + + final SQLiteDatabase db = mApgDatabase.getWritableDatabase(); + + Uri rowUri = null; + try { + final int match = sUriMatcher.match(uri); + + switch (match) { + case PUBLIC_KEY_RING: + values.put(PublicKeyRings.TYPE, KeyTypes.PUBLIC); + + db.insertOrThrow(Tables.KEY_RINGS, null, values); + rowUri = PublicKeyRings.buildPublicKeyRingsUri(values + .getAsString(PublicKeyRings._ID)); + + break; + case PUBLIC_KEY_RING_KEY: + values.put(PublicKeys.TYPE, KeyTypes.PUBLIC); + + db.insertOrThrow(Tables.KEYS, null, values); + rowUri = PublicKeys.buildPublicKeysUri(values.getAsString(PublicKeys._ID)); + + break; + case PUBLIC_KEY_RING_USER_ID: + db.insertOrThrow(Tables.USER_IDS, null, values); + rowUri = PublicUserIds.buildPublicUserIdsUri(values.getAsString(PublicUserIds._ID)); + + break; + case SECRET_KEY_RING: + values.put(SecretKeyRings.TYPE, KeyTypes.SECRET); + + db.insertOrThrow(Tables.KEY_RINGS, null, values); + rowUri = SecretKeyRings.buildSecretKeyRingsUri(values + .getAsString(SecretKeyRings._ID)); + + break; + case SECRET_KEY_RING_KEY: + values.put(SecretKeys.TYPE, KeyTypes.SECRET); + + db.insertOrThrow(Tables.KEYS, null, values); + rowUri = SecretKeys.buildSecretKeysUri(values.getAsString(SecretKeys._ID)); + + break; + case SECRET_KEY_RING_USER_ID: + db.insertOrThrow(Tables.USER_IDS, null, values); + rowUri = SecretUserIds.buildSecretUserIdsUri(values.getAsString(SecretUserIds._ID)); + + break; + default: + throw new UnsupportedOperationException("Unknown uri: " + uri); + } + } catch (SQLiteConstraintException e) { + Log.e(Constants.TAG, "Constraint exception on insert! Entry already existing?"); + } + + // notify of changes in db + getContext().getContentResolver().notifyChange(uri, null); + + return rowUri; + } + + /** {@inheritDoc} */ + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + Log.v(Constants.TAG, "delete(uri=" + uri + ")"); + + final SQLiteDatabase db = mApgDatabase.getWritableDatabase(); + + int count; + final int match = sUriMatcher.match(uri); + + switch (match) { + case PUBLIC_KEY_RING_ID: + // delete corresponding keys and userids + // db.delete(Tables.KEYS, whereClause, whereArgs) + // TODO + count = db.delete(Tables.KEY_RINGS, + buildDefaultSelection(uri, KeyTypes.PUBLIC, selection), selectionArgs); + break; + case SECRET_KEY_RING_ID: + // delete corresponding keys and userids + // TODO + count = db.delete(Tables.KEY_RINGS, + buildDefaultSelection(uri, KeyTypes.SECRET, selection), 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 = mApgDatabase.getWritableDatabase(); + + int count = 0; + try { + final int match = sUriMatcher.match(uri); + switch (match) { + case PUBLIC_KEY_RING_ID: + count = db.update(Tables.KEY_RINGS, values, + buildDefaultSelection(uri, KeyTypes.PUBLIC, selection), selectionArgs); + break; + case SECRET_KEY_RING_ID: + count = db.update(Tables.KEY_RINGS, values, + buildDefaultSelection(uri, KeyTypes.PUBLIC, selection), selectionArgs); + break; + default: + throw new UnsupportedOperationException("Unknown uri: " + uri); + } + } catch (SQLiteConstraintException e) { + Log.e(Constants.TAG, "Constraint exception on update! Entry already existing?"); + } + + // notify of changes in db + getContext().getContentResolver().notifyChange(uri, null); + + return count; + } + + /** + * Build default selection statement. If no extra selection is specified only build where clause + * with rowId + * + * @param uri + * @param selection + * @return + */ + private String buildDefaultSelection(Uri uri, Integer keyType, String selection) { + String rowId = uri.getPathSegments().get(1); + String andWhere = ""; + if (!TextUtils.isEmpty(selection)) { + andWhere = " AND (" + selection + ")"; + } + + String andType = ""; + if (keyType != null) { + andType = " AND " + KeyRingsColumns.TYPE + "=" + keyType; + } + + return BaseColumns._ID + "=" + rowId + andType + andWhere; + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + int match = sUriMatcher.match(uri); + if (match != DATA_STREAM) { + throw new FileNotFoundException(); + } + String fileName = uri.getPathSegments().get(1); + File file = new File(getContext().getFilesDir().getAbsolutePath(), fileName); + return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); + } +} diff --git a/org_apg/src/org/thialfihar/android/apg/provider/DataProvider.java b/org_apg/src/org/thialfihar/android/apg/provider/DataProvider.java deleted file mode 100644 index 9cf083528..000000000 --- a/org_apg/src/org/thialfihar/android/apg/provider/DataProvider.java +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * 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.thialfihar.android.apg.provider; - -import java.io.File; -import java.io.FileNotFoundException; -import java.util.HashMap; - -import org.thialfihar.android.apg.Id; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.content.UriMatcher; -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.database.sqlite.SQLiteQueryBuilder; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import android.text.TextUtils; - -public class DataProvider extends ContentProvider { - public static final String AUTHORITY = "org.thialfihar.android.apg.provider"; - - private static final int PUBLIC_KEY_RING = 101; - private static final int PUBLIC_KEY_RING_ID = 102; - private static final int PUBLIC_KEY_RING_BY_KEY_ID = 103; - private static final int PUBLIC_KEY_RING_BY_EMAILS = 104; - private static final int PUBLIC_KEY_RING_KEY = 111; - private static final int PUBLIC_KEY_RING_KEY_RANK = 112; - private static final int PUBLIC_KEY_RING_USER_ID = 121; - private static final int PUBLIC_KEY_RING_USER_ID_RANK = 122; - - private static final int SECRET_KEY_RING = 201; - private static final int SECRET_KEY_RING_ID = 202; - private static final int SECRET_KEY_RING_BY_KEY_ID = 203; - private static final int SECRET_KEY_RING_BY_EMAILS = 204; - private static final int SECRET_KEY_RING_KEY = 211; - private static final int SECRET_KEY_RING_KEY_RANK = 212; - private static final int SECRET_KEY_RING_USER_ID = 221; - private static final int SECRET_KEY_RING_USER_ID_RANK = 222; - - private static final int DATA_STREAM = 301; - - private static final String PUBLIC_KEY_RING_CONTENT_DIR_TYPE = - "vnd.android.cursor.dir/vnd.thialfihar.apg.public.key_ring"; - private static final String PUBLIC_KEY_RING_CONTENT_ITEM_TYPE = - "vnd.android.cursor.item/vnd.thialfihar.apg.public.key_ring"; - - private static final String PUBLIC_KEY_CONTENT_DIR_TYPE = - "vnd.android.cursor.dir/vnd.thialfihar.apg.public.key"; - private static final String PUBLIC_KEY_CONTENT_ITEM_TYPE = - "vnd.android.cursor.item/vnd.thialfihar.apg.public.key"; - - private static final String SECRET_KEY_RING_CONTENT_DIR_TYPE = - "vnd.android.cursor.dir/vnd.thialfihar.apg.secret.key_ring"; - private static final String SECRET_KEY_RING_CONTENT_ITEM_TYPE = - "vnd.android.cursor.item/vnd.thialfihar.apg.secret.key_ring"; - - private static final String SECRET_KEY_CONTENT_DIR_TYPE = - "vnd.android.cursor.dir/vnd.thialfihar.apg.secret.key"; - private static final String SECRET_KEY_CONTENT_ITEM_TYPE = - "vnd.android.cursor.item/vnd.thialfihar.apg.secret.key"; - - private static final String USER_ID_CONTENT_DIR_TYPE = - "vnd.android.cursor.dir/vnd.thialfihar.apg.user_id"; - private static final String USER_ID_CONTENT_ITEM_TYPE = - "vnd.android.cursor.item/vnd.thialfihar.apg.user_id"; - - public static final String _ID = "_id"; - public static final String MASTER_KEY_ID = "master_key_id"; - public static final String KEY_ID = "key_id"; - public static final String USER_ID = "user_id"; - - private static final UriMatcher mUriMatcher; - - private Database mDb; - - static { - mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - mUriMatcher.addURI(AUTHORITY, "key_rings/public/key_id/*", PUBLIC_KEY_RING_BY_KEY_ID); - mUriMatcher.addURI(AUTHORITY, "key_rings/public/emails/*", PUBLIC_KEY_RING_BY_EMAILS); - - mUriMatcher.addURI(AUTHORITY, "key_rings/public/*/keys", PUBLIC_KEY_RING_KEY); - mUriMatcher.addURI(AUTHORITY, "key_rings/public/*/keys/#", PUBLIC_KEY_RING_KEY_RANK); - - mUriMatcher.addURI(AUTHORITY, "key_rings/public/*/user_ids", PUBLIC_KEY_RING_USER_ID); - mUriMatcher.addURI(AUTHORITY, "key_rings/public/*/user_ids/#", PUBLIC_KEY_RING_USER_ID_RANK); - - mUriMatcher.addURI(AUTHORITY, "key_rings/public", PUBLIC_KEY_RING); - mUriMatcher.addURI(AUTHORITY, "key_rings/public/*", PUBLIC_KEY_RING_ID); - - mUriMatcher.addURI(AUTHORITY, "key_rings/secret/key_id/*", SECRET_KEY_RING_BY_KEY_ID); - mUriMatcher.addURI(AUTHORITY, "key_rings/secret/emails/*", SECRET_KEY_RING_BY_EMAILS); - - mUriMatcher.addURI(AUTHORITY, "key_rings/secret/*/keys", SECRET_KEY_RING_KEY); - mUriMatcher.addURI(AUTHORITY, "key_rings/secret/*/keys/#", SECRET_KEY_RING_KEY_RANK); - - mUriMatcher.addURI(AUTHORITY, "key_rings/secret/*/user_ids", SECRET_KEY_RING_USER_ID); - mUriMatcher.addURI(AUTHORITY, "key_rings/secret/*/user_ids/#", SECRET_KEY_RING_USER_ID_RANK); - - mUriMatcher.addURI(AUTHORITY, "key_rings/secret", SECRET_KEY_RING); - mUriMatcher.addURI(AUTHORITY, "key_rings/secret/*", SECRET_KEY_RING_ID); - - mUriMatcher.addURI(AUTHORITY, "data/*", DATA_STREAM); - } - - @Override - public boolean onCreate() { - mDb = new Database(getContext()); - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { - // TODO: implement the others, then use them for the lists - SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); - HashMap<String, String> projectionMap = new HashMap<String, String>(); - - int match = mUriMatcher.match(uri); - int type; - switch (match) { - case PUBLIC_KEY_RING: - case PUBLIC_KEY_RING_ID: - case PUBLIC_KEY_RING_BY_KEY_ID: - case PUBLIC_KEY_RING_BY_EMAILS: - case PUBLIC_KEY_RING_KEY: - case PUBLIC_KEY_RING_KEY_RANK: - case PUBLIC_KEY_RING_USER_ID: - case PUBLIC_KEY_RING_USER_ID_RANK: - type = Id.database.type_public; - break; - - case SECRET_KEY_RING: - case SECRET_KEY_RING_ID: - case SECRET_KEY_RING_BY_KEY_ID: - case SECRET_KEY_RING_BY_EMAILS: - case SECRET_KEY_RING_KEY: - case SECRET_KEY_RING_KEY_RANK: - case SECRET_KEY_RING_USER_ID: - case SECRET_KEY_RING_USER_ID_RANK: - type = Id.database.type_secret; - break; - - default: { - throw new IllegalArgumentException("Unknown URI " + uri); - } - } - - qb.appendWhere(KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = " + type); - - switch (match) { - case PUBLIC_KEY_RING_ID: - case SECRET_KEY_RING_ID: { - qb.appendWhere(" AND " + - KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(2)); - - // break omitted intentionally - } - - case PUBLIC_KEY_RING: - case SECRET_KEY_RING: { - qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " + - "(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + - Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " + - Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" + - ") " + - " INNER JOIN " + UserIds.TABLE_NAME + " ON " + - "(" + Keys.TABLE_NAME + "." + Keys._ID + " = " + - UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " + - UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') "); - - projectionMap.put(_ID, - KeyRings.TABLE_NAME + "." + KeyRings._ID); - projectionMap.put(MASTER_KEY_ID, - KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID); - projectionMap.put(USER_ID, - UserIds.TABLE_NAME + "." + UserIds.USER_ID); - - if (TextUtils.isEmpty(sortOrder)) { - sortOrder = UserIds.TABLE_NAME + "." + UserIds.USER_ID + " ASC"; - } - - break; - } - - case SECRET_KEY_RING_BY_KEY_ID: - case PUBLIC_KEY_RING_BY_KEY_ID: { - qb.setTables(Keys.TABLE_NAME + " AS tmp INNER JOIN " + - KeyRings.TABLE_NAME + " ON (" + - KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + - "tmp." + Keys.KEY_RING_ID + ")" + - " INNER JOIN " + Keys.TABLE_NAME + " ON " + - "(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + - Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " + - Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" + - ") " + - " INNER JOIN " + UserIds.TABLE_NAME + " ON " + - "(" + Keys.TABLE_NAME + "." + Keys._ID + " = " + - UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " + - UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') "); - - projectionMap.put(_ID, - KeyRings.TABLE_NAME + "." + KeyRings._ID); - projectionMap.put(MASTER_KEY_ID, - KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID); - projectionMap.put(USER_ID, - UserIds.TABLE_NAME + "." + UserIds.USER_ID); - - qb.appendWhere(" AND tmp." + Keys.KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(3)); - - break; - } - - case SECRET_KEY_RING_BY_EMAILS: - case PUBLIC_KEY_RING_BY_EMAILS: { - qb.setTables(KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " + - "(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + - Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " + - Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" + - ") " + - " INNER JOIN " + UserIds.TABLE_NAME + " ON " + - "(" + Keys.TABLE_NAME + "." + Keys._ID + " = " + - UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " + - UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') "); - - projectionMap.put(_ID, - KeyRings.TABLE_NAME + "." + KeyRings._ID); - projectionMap.put(MASTER_KEY_ID, - KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID); - projectionMap.put(USER_ID, - UserIds.TABLE_NAME + "." + UserIds.USER_ID); - - String emails = uri.getPathSegments().get(3); - 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." + UserIds.USER_ID + " LIKE "; - // match '*<email>', so it has to be at the *end* of the user id - emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">"); - gotCondition = true; - } - - if (gotCondition) { - qb.appendWhere(" AND EXISTS (SELECT tmp." + UserIds._ID + - " FROM " + UserIds.TABLE_NAME + - " AS tmp WHERE tmp." + UserIds.KEY_ID + " = " + - Keys.TABLE_NAME + "." + Keys._ID + - " AND (" + emailWhere + "))"); - } - - break; - } - - default: { - throw new IllegalArgumentException("Unknown URI " + uri); - } - } - - qb.setProjectionMap(projectionMap); - - // If no sort order is specified use the default - String orderBy; - if (TextUtils.isEmpty(sortOrder)) { - orderBy = null; - } else { - orderBy = sortOrder; - } - - //System.out.println(qb.buildQuery(projection, selection, selectionArgs, null, null, sortOrder, null).replace("WHERE", "WHERE\n")); - Cursor c = qb.query(mDb.db(), projection, selection, selectionArgs, null, null, orderBy); - - // Tell the cursor what uri to watch, so it knows when its source data changes - c.setNotificationUri(getContext().getContentResolver(), uri); - return c; - } - - @Override - public String getType(Uri uri) { - switch (mUriMatcher.match(uri)) { - case PUBLIC_KEY_RING: - case PUBLIC_KEY_RING_BY_EMAILS: - return PUBLIC_KEY_RING_CONTENT_DIR_TYPE; - - case PUBLIC_KEY_RING_ID: - return PUBLIC_KEY_RING_CONTENT_ITEM_TYPE; - - case PUBLIC_KEY_RING_BY_KEY_ID: - return PUBLIC_KEY_RING_CONTENT_ITEM_TYPE; - - case PUBLIC_KEY_RING_KEY: - return PUBLIC_KEY_CONTENT_DIR_TYPE; - - case PUBLIC_KEY_RING_KEY_RANK: - return PUBLIC_KEY_CONTENT_ITEM_TYPE; - - case PUBLIC_KEY_RING_USER_ID: - return USER_ID_CONTENT_DIR_TYPE; - - case PUBLIC_KEY_RING_USER_ID_RANK: - return USER_ID_CONTENT_ITEM_TYPE; - - case SECRET_KEY_RING: - case SECRET_KEY_RING_BY_EMAILS: - return SECRET_KEY_RING_CONTENT_DIR_TYPE; - - case SECRET_KEY_RING_ID: - return SECRET_KEY_RING_CONTENT_ITEM_TYPE; - - case SECRET_KEY_RING_BY_KEY_ID: - return SECRET_KEY_RING_CONTENT_ITEM_TYPE; - - case SECRET_KEY_RING_KEY: - return SECRET_KEY_CONTENT_DIR_TYPE; - - case SECRET_KEY_RING_KEY_RANK: - return SECRET_KEY_CONTENT_ITEM_TYPE; - - case SECRET_KEY_RING_USER_ID: - return USER_ID_CONTENT_DIR_TYPE; - - case SECRET_KEY_RING_USER_ID_RANK: - return USER_ID_CONTENT_ITEM_TYPE; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); - } - } - - @Override - public Uri insert(Uri uri, ContentValues initialValues) { - // not supported - return null; - } - - @Override - public int delete(Uri uri, String where, String[] whereArgs) { - // not supported - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { - // not supported - return 0; - } - - @Override - public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { - int match = mUriMatcher.match(uri); - if (match != DATA_STREAM) { - throw new FileNotFoundException(); - } - String fileName = uri.getPathSegments().get(1); - File file = new File(getContext().getFilesDir().getAbsolutePath(), fileName); - return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); - } -} diff --git a/org_apg/src/org/thialfihar/android/apg/provider/Database.java b/org_apg/src/org/thialfihar/android/apg/provider/Database.java deleted file mode 100644 index 0c14283c2..000000000 --- a/org_apg/src/org/thialfihar/android/apg/provider/Database.java +++ /dev/null @@ -1,617 +0,0 @@ -/* - * 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.thialfihar.android.apg.provider; - -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.thialfihar.android.apg.Id; -import org.thialfihar.android.apg.helper.PGPHelper; -import org.thialfihar.android.apg.util.IterableIterator; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import org.thialfihar.android.apg.util.Log; - -import java.io.IOException; -import java.util.Date; -import java.util.HashMap; -import java.util.Vector; - -public class Database extends SQLiteOpenHelper { - public static class GeneralException extends Exception { - static final long serialVersionUID = 0xf812773343L; - - public GeneralException(String message) { - super(message); - } - } - - private static final String DATABASE_NAME = "apg"; - private static final int DATABASE_VERSION = 2; - - public static final String AUTHORITY = "org.thialfihar.android.apg.database"; - - public static HashMap<String, String> sKeyRingsProjection; - public static HashMap<String, String> sKeysProjection; - public static HashMap<String, String> sUserIdsProjection; - - private SQLiteDatabase mDb = null; - private int mStatus = 0; - - static { - sKeyRingsProjection = new HashMap<String, String>(); - sKeyRingsProjection.put(KeyRings._ID, KeyRings._ID); - sKeyRingsProjection.put(KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID); - sKeyRingsProjection.put(KeyRings.TYPE, KeyRings.TYPE); - sKeyRingsProjection.put(KeyRings.WHO_ID, KeyRings.WHO_ID); - sKeyRingsProjection.put(KeyRings.KEY_RING_DATA, KeyRings.KEY_RING_DATA); - - sKeysProjection = new HashMap<String, String>(); - sKeysProjection.put(Keys._ID, Keys._ID); - sKeysProjection.put(Keys.KEY_ID, Keys.KEY_ID); - sKeysProjection.put(Keys.TYPE, Keys.TYPE); - sKeysProjection.put(Keys.IS_MASTER_KEY, Keys.IS_MASTER_KEY); - sKeysProjection.put(Keys.ALGORITHM, Keys.ALGORITHM); - sKeysProjection.put(Keys.KEY_SIZE, Keys.KEY_SIZE); - sKeysProjection.put(Keys.CAN_SIGN, Keys.CAN_SIGN); - sKeysProjection.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT); - sKeysProjection.put(Keys.IS_REVOKED, Keys.IS_REVOKED); - sKeysProjection.put(Keys.CREATION, Keys.CREATION); - sKeysProjection.put(Keys.EXPIRY, Keys.EXPIRY); - sKeysProjection.put(Keys.KEY_DATA, Keys.KEY_DATA); - sKeysProjection.put(Keys.RANK, Keys.RANK); - - sUserIdsProjection = new HashMap<String, String>(); - sUserIdsProjection.put(UserIds._ID, UserIds._ID); - sUserIdsProjection.put(UserIds.KEY_ID, UserIds.KEY_ID); - sUserIdsProjection.put(UserIds.USER_ID, UserIds.USER_ID); - sUserIdsProjection.put(UserIds.RANK, UserIds.RANK); - } - - public Database(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - // force upgrade to test things - //onUpgrade(getWritableDatabase(), 1, 2); - mDb = getWritableDatabase(); - } - - @Override - protected void finalize() throws Throwable { - mDb.close(); - super.finalize(); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + KeyRings.TABLE_NAME + " (" + - KeyRings._ID + " " + KeyRings._ID_type + "," + - KeyRings.MASTER_KEY_ID + " " + KeyRings.MASTER_KEY_ID_type + ", " + - KeyRings.TYPE + " " + KeyRings.TYPE_type + ", " + - KeyRings.WHO_ID + " " + KeyRings.WHO_ID_type + ", " + - KeyRings.KEY_RING_DATA + " " + KeyRings.KEY_RING_DATA_type + ");"); - - db.execSQL("CREATE TABLE " + Keys.TABLE_NAME + " (" + - Keys._ID + " " + Keys._ID_type + "," + - Keys.KEY_ID + " " + Keys.KEY_ID_type + ", " + - Keys.TYPE + " " + Keys.TYPE_type + ", " + - Keys.IS_MASTER_KEY + " " + Keys.IS_MASTER_KEY_type + ", " + - Keys.ALGORITHM + " " + Keys.ALGORITHM_type + ", " + - Keys.KEY_SIZE + " " + Keys.KEY_SIZE_type + ", " + - Keys.CAN_SIGN + " " + Keys.CAN_SIGN_type + ", " + - Keys.CAN_ENCRYPT + " " + Keys.CAN_ENCRYPT_type + ", " + - Keys.IS_REVOKED + " " + Keys.IS_REVOKED_type + ", " + - Keys.CREATION + " " + Keys.CREATION_type + ", " + - Keys.EXPIRY + " " + Keys.EXPIRY_type + ", " + - Keys.KEY_RING_ID + " " + Keys.KEY_RING_ID_type + ", " + - Keys.KEY_DATA + " " + Keys.KEY_DATA_type + - Keys.RANK + " " + Keys.RANK_type + ");"); - - db.execSQL("CREATE TABLE " + UserIds.TABLE_NAME + " (" + - UserIds._ID + " " + UserIds._ID_type + "," + - UserIds.KEY_ID + " " + UserIds.KEY_ID_type + "," + - UserIds.USER_ID + " " + UserIds.USER_ID_type + "," + - UserIds.RANK + " " + UserIds.RANK_type + ");"); - - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - mDb = db; - for (int version = oldVersion; version < newVersion; ++version) { - switch (version) { - case 1: { // upgrade 1 to 2 - db.execSQL("DROP TABLE IF EXISTS " + KeyRings.TABLE_NAME + ";"); - db.execSQL("DROP TABLE IF EXISTS " + Keys.TABLE_NAME + ";"); - db.execSQL("DROP TABLE IF EXISTS " + UserIds.TABLE_NAME + ";"); - - db.execSQL("CREATE TABLE " + KeyRings.TABLE_NAME + " (" + - KeyRings._ID + " " + KeyRings._ID_type + "," + - KeyRings.MASTER_KEY_ID + " " + KeyRings.MASTER_KEY_ID_type + ", " + - KeyRings.TYPE + " " + KeyRings.TYPE_type + ", " + - KeyRings.WHO_ID + " " + KeyRings.WHO_ID_type + ", " + - KeyRings.KEY_RING_DATA + " " + KeyRings.KEY_RING_DATA_type + ");"); - - - db.execSQL("CREATE TABLE " + Keys.TABLE_NAME + " (" + - Keys._ID + " " + Keys._ID_type + "," + - Keys.KEY_ID + " " + Keys.KEY_ID_type + ", " + - Keys.TYPE + " " + Keys.TYPE_type + ", " + - Keys.IS_MASTER_KEY + " " + Keys.IS_MASTER_KEY_type + ", " + - Keys.ALGORITHM + " " + Keys.ALGORITHM_type + ", " + - Keys.KEY_SIZE + " " + Keys.KEY_SIZE_type + ", " + - Keys.CAN_SIGN + " " + Keys.CAN_SIGN_type + ", " + - Keys.CAN_ENCRYPT + " " + Keys.CAN_ENCRYPT_type + ", " + - Keys.IS_REVOKED + " " + Keys.IS_REVOKED_type + ", " + - Keys.CREATION + " " + Keys.CREATION_type + ", " + - Keys.EXPIRY + " " + Keys.EXPIRY_type + ", " + - Keys.KEY_RING_ID + " " + Keys.KEY_RING_ID_type + ", " + - Keys.KEY_DATA + " " + Keys.KEY_DATA_type + - Keys.RANK + " " + Keys.RANK_type + ");"); - - db.execSQL("CREATE TABLE " + UserIds.TABLE_NAME + " (" + - UserIds._ID + " " + UserIds._ID_type + "," + - UserIds.KEY_ID + " " + UserIds.KEY_ID_type + "," + - UserIds.USER_ID + " " + UserIds.USER_ID_type + "," + - UserIds.RANK + " " + UserIds.RANK_type + ");"); - - Cursor cursor = db.query("public_keys", new String[] { "c_key_data" }, - null, null, null, null, null); - if (cursor != null && cursor.moveToFirst()) { - do { - byte[] data = cursor.getBlob(0); - try { - PGPPublicKeyRing keyRing = new PGPPublicKeyRing(data); - saveKeyRing(keyRing); - } catch (IOException e) { - Log.e("apg.db.upgrade", "key import failed: " + e); - } catch (GeneralException e) { - Log.e("apg.db.upgrade", "key import failed: " + e); - } - } while (cursor.moveToNext()); - } - - if (cursor != null) { - cursor.close(); - } - - cursor = db.query("secret_keys", new String[]{ "c_key_data" }, - null, null, null, null, null); - if (cursor != null && cursor.moveToFirst()) { - do { - byte[] data = cursor.getBlob(0); - try { - PGPSecretKeyRing keyRing = new PGPSecretKeyRing(data); - saveKeyRing(keyRing); - } catch (IOException e) { - Log.e("apg.db.upgrade", "key import failed: " + e); - } catch (PGPException e) { - Log.e("apg.db.upgrade", "key import failed: " + e); - } catch (GeneralException e) { - Log.e("apg.db.upgrade", "key import failed: " + e); - } - } while (cursor.moveToNext()); - } - - if (cursor != null) { - cursor.close(); - } - - db.execSQL("DROP TABLE IF EXISTS public_keys;"); - db.execSQL("DROP TABLE IF EXISTS secret_keys;"); - - break; - } - - default: { - break; - } - } - } - mDb = null; - } - - public int saveKeyRing(PGPPublicKeyRing keyRing) throws IOException, GeneralException { - mDb.beginTransaction(); - ContentValues values = new ContentValues(); - PGPPublicKey masterKey = keyRing.getPublicKey(); - long masterKeyId = masterKey.getKeyID(); - - values.put(KeyRings.MASTER_KEY_ID, masterKeyId); - values.put(KeyRings.TYPE, Id.database.type_public); - values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded()); - - long rowId = insertOrUpdateKeyRing(values); - int returnValue = mStatus; - - if (rowId == -1) { - throw new GeneralException("saving public key ring " + masterKeyId + " failed"); - } - - Vector<Integer> seenIds = new Vector<Integer>(); - int rank = 0; - for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) { - seenIds.add(saveKey(rowId, key, rank)); - ++rank; - } - - String seenIdsStr = ""; - for (Integer id : seenIds) { - if (seenIdsStr.length() > 0) { - seenIdsStr += ","; - } - seenIdsStr += id; - } - mDb.delete(Keys.TABLE_NAME, - Keys.KEY_RING_ID + " = ? AND " + - Keys._ID + " NOT IN (" + seenIdsStr + ")", - new String[] { "" + rowId }); - - mDb.setTransactionSuccessful(); - mDb.endTransaction(); - return returnValue; - } - - public int saveKeyRing(PGPSecretKeyRing keyRing) throws IOException, GeneralException { - mDb.beginTransaction(); - ContentValues values = new ContentValues(); - PGPSecretKey masterKey = keyRing.getSecretKey(); - long masterKeyId = masterKey.getKeyID(); - - values.put(KeyRings.MASTER_KEY_ID, masterKeyId); - values.put(KeyRings.TYPE, Id.database.type_secret); - values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded()); - - long rowId = insertOrUpdateKeyRing(values); - int returnValue = mStatus; - - if (rowId == -1) { - throw new GeneralException("saving secret key ring " + masterKeyId + " failed"); - } - - Vector<Integer> seenIds = new Vector<Integer>(); - int rank = 0; - for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) { - seenIds.add(saveKey(rowId, key, rank)); - ++rank; - } - - String seenIdsStr = ""; - for (Integer id : seenIds) { - if (seenIdsStr.length() > 0) { - seenIdsStr += ","; - } - seenIdsStr += id; - } - mDb.delete(Keys.TABLE_NAME, - Keys.KEY_RING_ID + " = ? AND " + - Keys._ID + " NOT IN (" + seenIdsStr + ")", - new String[] { "" + rowId }); - - mDb.setTransactionSuccessful(); - mDb.endTransaction(); - return returnValue; - } - - private int saveKey(long keyRingId, PGPPublicKey key, int rank) - throws IOException, GeneralException { - ContentValues values = new ContentValues(); - - values.put(Keys.KEY_ID, key.getKeyID()); - values.put(Keys.TYPE, Id.database.type_public); - values.put(Keys.IS_MASTER_KEY, key.isMasterKey()); - values.put(Keys.ALGORITHM, key.getAlgorithm()); - values.put(Keys.KEY_SIZE, key.getBitStrength()); - values.put(Keys.CAN_SIGN, PGPHelper.isSigningKey(key)); - values.put(Keys.CAN_ENCRYPT, PGPHelper.isEncryptionKey(key)); - values.put(Keys.IS_REVOKED, key.isRevoked()); - values.put(Keys.CREATION, PGPHelper.getCreationDate(key).getTime() / 1000); - Date expiryDate = PGPHelper.getExpiryDate(key); - if (expiryDate != null) { - values.put(Keys.EXPIRY, expiryDate.getTime() / 1000); - } - values.put(Keys.KEY_RING_ID, keyRingId); - values.put(Keys.KEY_DATA, key.getEncoded()); - values.put(Keys.RANK, rank); - - long rowId = insertOrUpdateKey(values); - - if (rowId == -1) { - throw new GeneralException("saving public key " + key.getKeyID() + " failed"); - } - - Vector<Integer> seenIds = new Vector<Integer>(); - int userIdRank = 0; - for (String userId : new IterableIterator<String>(key.getUserIDs())) { - seenIds.add(saveUserId(rowId, userId, userIdRank)); - ++userIdRank; - } - - String seenIdsStr = ""; - for (Integer id : seenIds) { - if (seenIdsStr.length() > 0) { - seenIdsStr += ","; - } - seenIdsStr += id; - } - mDb.delete(UserIds.TABLE_NAME, - UserIds.KEY_ID + " = ? AND " + - UserIds._ID + " NOT IN (" + seenIdsStr + ")", - new String[] { "" + rowId }); - - return (int)rowId; - } - - private int saveKey(long keyRingId, PGPSecretKey key, int rank) - throws IOException, GeneralException { - ContentValues values = new ContentValues(); - - values.put(Keys.KEY_ID, key.getPublicKey().getKeyID()); - values.put(Keys.TYPE, Id.database.type_secret); - values.put(Keys.IS_MASTER_KEY, key.isMasterKey()); - values.put(Keys.ALGORITHM, key.getPublicKey().getAlgorithm()); - values.put(Keys.KEY_SIZE, key.getPublicKey().getBitStrength()); - values.put(Keys.CAN_SIGN, PGPHelper.isSigningKey(key)); - values.put(Keys.CAN_ENCRYPT, PGPHelper.isEncryptionKey(key)); - values.put(Keys.IS_REVOKED, key.getPublicKey().isRevoked()); - values.put(Keys.CREATION, PGPHelper.getCreationDate(key).getTime() / 1000); - Date expiryDate = PGPHelper.getExpiryDate(key); - if (expiryDate != null) { - values.put(Keys.EXPIRY, expiryDate.getTime() / 1000); - } - values.put(Keys.KEY_RING_ID, keyRingId); - values.put(Keys.KEY_DATA, key.getEncoded()); - values.put(Keys.RANK, rank); - - long rowId = insertOrUpdateKey(values); - - if (rowId == -1) { - throw new GeneralException("saving secret key " + key.getPublicKey().getKeyID() + " failed"); - } - - Vector<Integer> seenIds = new Vector<Integer>(); - int userIdRank = 0; - for (String userId : new IterableIterator<String>(key.getUserIDs())) { - seenIds.add(saveUserId(rowId, userId, userIdRank)); - ++userIdRank; - } - - String seenIdsStr = ""; - for (Integer id : seenIds) { - if (seenIdsStr.length() > 0) { - seenIdsStr += ","; - } - seenIdsStr += id; - } - mDb.delete(UserIds.TABLE_NAME, - UserIds.KEY_ID + " = ? AND " + - UserIds._ID + " NOT IN (" + seenIdsStr + ")", - new String[] { "" + rowId }); - - return (int)rowId; - } - - private int saveUserId(long keyId, String userId, int rank) throws GeneralException { - ContentValues values = new ContentValues(); - - values.put(UserIds.KEY_ID, keyId); - values.put(UserIds.USER_ID, userId); - values.put(UserIds.RANK, rank); - - long rowId = insertOrUpdateUserId(values); - - if (rowId == -1) { - throw new GeneralException("saving user id " + userId + " failed"); - } - - return (int)rowId; - } - - private long insertOrUpdateKeyRing(ContentValues values) { - Cursor c = mDb.query(KeyRings.TABLE_NAME, new String[] { KeyRings._ID }, - KeyRings.MASTER_KEY_ID + " = ? AND " + KeyRings.TYPE + " = ?", - new String[] { - values.getAsString(KeyRings.MASTER_KEY_ID), - values.getAsString(KeyRings.TYPE), - }, - null, null, null); - long rowId = -1; - if (c != null && c.moveToFirst()) { - rowId = c.getLong(0); - mDb.update(KeyRings.TABLE_NAME, values, - KeyRings._ID + " = ?", new String[] { "" + rowId }); - mStatus = Id.return_value.updated; - } else { - rowId = mDb.insert(KeyRings.TABLE_NAME, KeyRings.WHO_ID, values); - mStatus = Id.return_value.ok; - } - - if (c != null) { - c.close(); - } - - return rowId; - } - - private long insertOrUpdateKey(ContentValues values) { - Cursor c = mDb.query(Keys.TABLE_NAME, new String[] { Keys._ID }, - Keys.KEY_ID + " = ? AND " + Keys.TYPE + " = ?", - new String[] { - values.getAsString(Keys.KEY_ID), - values.getAsString(Keys.TYPE), - }, - null, null, null); - long rowId = -1; - if (c != null && c.moveToFirst()) { - rowId = c.getLong(0); - mDb.update(Keys.TABLE_NAME, values, - Keys._ID + " = ?", new String[] { "" + rowId }); - } else { - rowId = mDb.insert(Keys.TABLE_NAME, Keys.KEY_DATA, values); - } - - if (c != null) { - c.close(); - } - - return rowId; - } - - private long insertOrUpdateUserId(ContentValues values) { - Cursor c = mDb.query(UserIds.TABLE_NAME, new String[] { UserIds._ID }, - UserIds.KEY_ID + " = ? AND " + UserIds.USER_ID + " = ?", - new String[] { - values.getAsString(UserIds.KEY_ID), - values.getAsString(UserIds.USER_ID), - }, - null, null, null); - long rowId = -1; - if (c != null && c.moveToFirst()) { - rowId = c.getLong(0); - mDb.update(UserIds.TABLE_NAME, values, - UserIds._ID + " = ?", new String[] { "" + rowId }); - } else { - rowId = mDb.insert(UserIds.TABLE_NAME, UserIds.USER_ID, values); - } - - if (c != null) { - c.close(); - } - - return rowId; - } - - public Object getKeyRing(int keyRingId) { - Cursor c = mDb.query(KeyRings.TABLE_NAME, - new String[] { KeyRings.KEY_RING_DATA, KeyRings.TYPE }, - KeyRings._ID + " = ?", - new String[] { - "" + keyRingId, - }, - null, null, null); - byte[] data = null; - Object keyRing = null; - if (c != null && c.moveToFirst()) { - data = c.getBlob(0); - if (data != null) { - try { - if (c.getInt(1) == Id.database.type_public) { - keyRing = new PGPPublicKeyRing(data); - } else { - keyRing = new PGPSecretKeyRing(data); - } - } catch (IOException e) { - // can't load it, then - } catch (PGPException e) { - // can't load it, then - } - } - } - - if (c != null) { - c.close(); - } - - return keyRing; - } - - public byte[] getKeyRingDataFromKeyId(int type, long keyId) { - Cursor c = mDb.query(Keys.TABLE_NAME + " INNER JOIN " + KeyRings.TABLE_NAME + " ON (" + - KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " + - Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + ")", - new String[] { KeyRings.TABLE_NAME + "." + KeyRings.KEY_RING_DATA }, - Keys.TABLE_NAME + "." + Keys.KEY_ID + " = ? AND " + - KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?", - new String[] { - "" + keyId, - "" + type, - }, - null, null, null); - - byte[] data = null; - if (c != null && c.moveToFirst()) { - data = c.getBlob(0); - } - - if (c != null) { - c.close(); - } - - return data; - } - - public byte[] getKeyDataFromKeyId(int type, long keyId) { - Cursor c = mDb.query(Keys.TABLE_NAME, new String[] { Keys.KEY_DATA }, - Keys.KEY_ID + " = ? AND " + Keys.TYPE + " = ?", - new String[] { - "" + keyId, - "" + type, - }, - null, null, null); - byte[] data = null; - if (c != null && c.moveToFirst()) { - data = c.getBlob(0); - } - - if (c != null) { - c.close(); - } - - return data; - } - - public void deleteKeyRing(int keyRingId) { - mDb.beginTransaction(); - mDb.delete(KeyRings.TABLE_NAME, - KeyRings._ID + " = ?", new String[] { "" + keyRingId }); - - Cursor c = mDb.query(Keys.TABLE_NAME, new String[] { Keys._ID }, - Keys.KEY_RING_ID + " = ?", - new String[] { - "" + keyRingId, - }, - null, null, null); - if (c != null && c.moveToFirst()) { - do { - int keyId = c.getInt(0); - deleteKey(keyId); - } while (c.moveToNext()); - } - - if (c != null) { - c.close(); - } - - mDb.setTransactionSuccessful(); - mDb.endTransaction(); - } - - private void deleteKey(int keyId) { - mDb.delete(Keys.TABLE_NAME, - Keys._ID + " = ?", new String[] { "" + keyId }); - - mDb.delete(UserIds.TABLE_NAME, - UserIds.KEY_ID + " = ?", new String[] { "" + keyId }); - } - - public SQLiteDatabase db() { - return mDb; - } -} diff --git a/org_apg/src/org/thialfihar/android/apg/provider/KeyRings.java b/org_apg/src/org/thialfihar/android/apg/provider/KeyRings.java deleted file mode 100644 index 58e95eba6..000000000 --- a/org_apg/src/org/thialfihar/android/apg/provider/KeyRings.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * 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.thialfihar.android.apg.provider; - -import android.provider.BaseColumns; - -public class KeyRings implements BaseColumns { - public static final String TABLE_NAME = "key_rings"; - - public static final String _ID_type = "INTEGER PRIMARY KEY"; - public static final String MASTER_KEY_ID = "c_master_key_id"; - public static final String MASTER_KEY_ID_type = "INT64"; - public static final String TYPE = "c_type"; - public static final String TYPE_type = "INTEGER"; - public static final String WHO_ID = "c_who_id"; - public static final String WHO_ID_type = "INTEGER"; - public static final String KEY_RING_DATA = "c_key_ring_data"; - public static final String KEY_RING_DATA_type = "BLOB"; -} diff --git a/org_apg/src/org/thialfihar/android/apg/provider/Keys.java b/org_apg/src/org/thialfihar/android/apg/provider/Keys.java deleted file mode 100644 index 618c5e920..000000000 --- a/org_apg/src/org/thialfihar/android/apg/provider/Keys.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * 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.thialfihar.android.apg.provider; - -import android.provider.BaseColumns; - -public class Keys implements BaseColumns { - public static final String TABLE_NAME = "keys"; - - public static final String _ID_type = "INTEGER PRIMARY KEY"; - public static final String KEY_ID = "c_key_id"; - public static final String KEY_ID_type = "INT64"; - public static final String TYPE = "c_type"; - public static final String TYPE_type = "INTEGER"; - public static final String IS_MASTER_KEY = "c_is_master_key"; - public static final String IS_MASTER_KEY_type = "INTEGER"; - public static final String ALGORITHM = "c_algorithm"; - public static final String ALGORITHM_type = "INTEGER"; - public static final String KEY_SIZE = "c_key_size"; - public static final String KEY_SIZE_type = "INTEGER"; - public static final String CAN_SIGN = "c_can_sign"; - public static final String CAN_SIGN_type = "INTEGER"; - public static final String CAN_ENCRYPT = "c_can_encrypt"; - public static final String CAN_ENCRYPT_type = "INTEGER"; - public static final String IS_REVOKED = "c_is_revoked"; - public static final String IS_REVOKED_type = "INTEGER"; - public static final String CREATION = "c_creation"; - public static final String CREATION_type = "INTEGER"; - public static final String EXPIRY = "c_expiry"; - public static final String EXPIRY_type = "INTEGER"; - public static final String KEY_RING_ID = "c_key_ring_id"; - public static final String KEY_RING_ID_type = "INTEGER"; - public static final String KEY_DATA = "c_key_data"; - public static final String KEY_DATA_type = "BLOB"; - public static final String RANK = "c_key_data"; - public static final String RANK_type = "INTEGER"; -} diff --git a/org_apg/src/org/thialfihar/android/apg/provider/ProviderHelper.java b/org_apg/src/org/thialfihar/android/apg/provider/ProviderHelper.java new file mode 100644 index 000000000..234f96bd0 --- /dev/null +++ b/org_apg/src/org/thialfihar/android/apg/provider/ProviderHelper.java @@ -0,0 +1,79 @@ +package org.thialfihar.android.apg.provider; + +import java.io.IOException; + +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.thialfihar.android.apg.helper.PGPMain.ApgGeneralException; +import org.thialfihar.android.apg.provider.ApgContract.PublicKeyRings; +import org.thialfihar.android.apg.provider.ApgContract.PublicKeys; +import org.thialfihar.android.apg.provider.ApgContract.SecretKeys; + +import android.content.ContentValues; +import android.content.Context; + +public class ProviderHelper { + // public static void insertHostsSource(Context context, String url) { + // ContentValues values = new ContentValues(); + // values.put(HostsSources.URL, url); + // values.put(HostsSources.ENABLED, true); // default is enabled + // values.put(HostsSources.LAST_MODIFIED_LOCAL, 0); // last_modified_local starts at 0 + // values.put(HostsSources.LAST_MODIFIED_ONLINE, 0); // last_modified_onlinestarts at 0 + // context.getContentResolver().insert(HostsSources.CONTENT_URI, values); + // } + + // public int saveKeyRing(Context context, PGPPublicKeyRing keyRing) throws IOException, + // ApgGeneralException { + // // mDb.beginTransaction(); + // ContentValues values = new ContentValues(); + // PGPPublicKey masterKey = keyRing.getPublicKey(); + // long masterKeyId = masterKey.getKeyID(); + // + // values.put(PublicKeyRings.MASTER_KEY_ID, masterKeyId); + // // values.put(KeyRings.TYPE, Id.database.type_public); + // values.put(PublicKeyRings.KEY_RING_DATA, keyRing.getEncoded()); + // + // context.getContentResolver().insert(PublicKeyRings.CONTENT_URI, values); + // + // long rowId = insertOrUpdateKeyRing(values); + // int returnValue = mStatus; + // + // if (rowId == -1) { + // throw new ApgGeneralException("saving public key ring " + masterKeyId + " failed"); + // } + // + // Vector<Integer> seenIds = new Vector<Integer>(); + // int rank = 0; + // for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) { + // seenIds.add(saveKey(rowId, key, rank)); + // ++rank; + // } + // + // String seenIdsStr = ""; + // for (Integer id : seenIds) { + // if (seenIdsStr.length() > 0) { + // seenIdsStr += ","; + // } + // seenIdsStr += id; + // } + // mDb.delete(Keys.TABLE_NAME, Keys.KEY_RING_ID + " = ? AND " + Keys._ID + " NOT IN (" + // + seenIdsStr + ")", new String[] { "" + rowId }); + // + // mDb.setTransactionSuccessful(); + // mDb.endTransaction(); + // return returnValue; + // } + + /** + * Deletes public and secret keys + * + * @param context + * @param rowId + */ + public static void deleteKey(Context context, long rowId) { + context.getContentResolver().delete(PublicKeys.buildPublicKeysUri(Long.toString(rowId)), + null, null); + context.getContentResolver().delete(SecretKeys.buildSecretKeysUri(Long.toString(rowId)), + null, null); + } +} diff --git a/org_apg/src/org/thialfihar/android/apg/provider/UserIds.java b/org_apg/src/org/thialfihar/android/apg/provider/UserIds.java deleted file mode 100644 index 2050ccf9c..000000000 --- a/org_apg/src/org/thialfihar/android/apg/provider/UserIds.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * 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.thialfihar.android.apg.provider; - -import android.provider.BaseColumns; - -public class UserIds implements BaseColumns { - public static final String TABLE_NAME = "user_ids"; - - public static final String _ID_type = "INTEGER PRIMARY KEY"; - public static final String KEY_ID = "c_key_id"; - public static final String KEY_ID_type = "INTEGER"; - public static final String USER_ID = "c_user_id"; - public static final String USER_ID_type = "TEXT"; - public static final String RANK = "c_rank"; - public static final String RANK_type = "INTEGER"; -} |