From 4177f7159c96ad964817770e06f3d3727e582684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 18 Jan 2013 23:51:44 +0100 Subject: [PATCH] New broadcast on database change to inform other apps --- .../KeychainContentProviderHelper.java | 13 +- .../keychain/provider/KeychainProvider.java | 129 +++++++++++------- README.md | 27 ++-- 3 files changed, 109 insertions(+), 60 deletions(-) diff --git a/OpenPGP-Keychain-API-Lib/src/org/sufficientlysecure/keychain/integration/KeychainContentProviderHelper.java b/OpenPGP-Keychain-API-Lib/src/org/sufficientlysecure/keychain/integration/KeychainContentProviderHelper.java index bc2a4ad7a..0b9211748 100644 --- a/OpenPGP-Keychain-API-Lib/src/org/sufficientlysecure/keychain/integration/KeychainContentProviderHelper.java +++ b/OpenPGP-Keychain-API-Lib/src/org/sufficientlysecure/keychain/integration/KeychainContentProviderHelper.java @@ -235,11 +235,18 @@ public class KeychainContentProviderHelper { * @param keyId * @return user id */ - public String getUserId(long keyId) { + public String getUserId(long keyId, boolean secretKeyrings) { String userId = null; try { - Uri contentUri = ContentUris.withAppendedId(CONTENT_URI_SECRET_KEY_RING_BY_KEY_ID, - keyId); + Uri contentUri = null; + if (secretKeyrings) { + contentUri = ContentUris.withAppendedId(CONTENT_URI_SECRET_KEY_RING_BY_KEY_ID, + keyId); + } else { + contentUri = ContentUris.withAppendedId(CONTENT_URI_PUBLIC_KEY_RING_BY_KEY_ID, + keyId); + } + Cursor c = mContext.getContentResolver().query(contentUri, new String[] { "user_id" }, null, null, null); if (c != null && c.moveToFirst()) { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 9d531dceb..04df935c9 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -35,6 +35,7 @@ import org.sufficientlysecure.keychain.util.Log; import android.content.ContentProvider; import android.content.ContentValues; +import android.content.Intent; import android.content.UriMatcher; import android.database.Cursor; import android.database.DatabaseUtils; @@ -47,6 +48,9 @@ import android.provider.BaseColumns; import android.text.TextUtils; public class KeychainProvider extends ContentProvider { + public static final String ACTION_BROADCAST_DATABASE_CHANGE = Constants.PACKAGE_NAME + + ".action.DATABASE_CHANGE"; + private static final int PUBLIC_KEY_RING = 101; private static final int PUBLIC_KEY_RING_BY_ROW_ID = 102; private static final int PUBLIC_KEY_RING_BY_MASTER_KEY_ID = 103; @@ -104,22 +108,26 @@ public class KeychainProvider extends ContentProvider { * key_rings/public/like_email/_ * */ - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC, - PUBLIC_KEY_RING); - matcher.addURI(authority, - KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/#", - PUBLIC_KEY_RING_BY_ROW_ID); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/" - + KeychainContract.PATH_BY_MASTER_KEY_ID + "/*", PUBLIC_KEY_RING_BY_MASTER_KEY_ID); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/" - + KeychainContract.PATH_BY_KEY_ID + "/*", PUBLIC_KEY_RING_BY_KEY_ID); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/" - + KeychainContract.PATH_BY_EMAILS + "/*", PUBLIC_KEY_RING_BY_EMAILS); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/" - + KeychainContract.PATH_BY_EMAILS, PUBLIC_KEY_RING_BY_EMAILS); // without emails - // specified - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/" - + KeychainContract.PATH_BY_LIKE_EMAIL + "/*", PUBLIC_KEY_RING_BY_LIKE_EMAIL); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_PUBLIC, PUBLIC_KEY_RING); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_PUBLIC + "/#", PUBLIC_KEY_RING_BY_ROW_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_MASTER_KEY_ID + + "/*", PUBLIC_KEY_RING_BY_MASTER_KEY_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_KEY_ID + "/*", + PUBLIC_KEY_RING_BY_KEY_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_EMAILS + "/*", + PUBLIC_KEY_RING_BY_EMAILS); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_EMAILS, + PUBLIC_KEY_RING_BY_EMAILS); // without emails + // specified + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_LIKE_EMAIL + "/*", + PUBLIC_KEY_RING_BY_LIKE_EMAIL); /** * public keys @@ -129,10 +137,12 @@ public class KeychainProvider extends ContentProvider { * key_rings/public/#/keys/# * */ - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC - + "/#/" + KeychainContract.PATH_KEYS, PUBLIC_KEY_RING_KEY); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC - + "/#/" + KeychainContract.PATH_KEYS + "/#", PUBLIC_KEY_RING_KEY_BY_ROW_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_PUBLIC + "/#/" + KeychainContract.PATH_KEYS, + PUBLIC_KEY_RING_KEY); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_PUBLIC + "/#/" + KeychainContract.PATH_KEYS + "/#", + PUBLIC_KEY_RING_KEY_BY_ROW_ID); /** * public user ids @@ -142,10 +152,12 @@ public class KeychainProvider extends ContentProvider { * key_rings/public/#/user_ids/# * */ - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC - + "/#/" + KeychainContract.PATH_USER_IDS, PUBLIC_KEY_RING_USER_ID); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC - + "/#/" + KeychainContract.PATH_USER_IDS + "/#", PUBLIC_KEY_RING_USER_ID_BY_ROW_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_PUBLIC + "/#/" + KeychainContract.PATH_USER_IDS, + PUBLIC_KEY_RING_USER_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_PUBLIC + "/#/" + KeychainContract.PATH_USER_IDS + "/#", + PUBLIC_KEY_RING_USER_ID_BY_ROW_ID); /** * secret key rings @@ -159,22 +171,26 @@ public class KeychainProvider extends ContentProvider { * key_rings/secret/like_email/_ * */ - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET, - SECRET_KEY_RING); - matcher.addURI(authority, - KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/#", - SECRET_KEY_RING_BY_ROW_ID); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/" - + KeychainContract.PATH_BY_MASTER_KEY_ID + "/*", SECRET_KEY_RING_BY_MASTER_KEY_ID); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/" - + KeychainContract.PATH_BY_KEY_ID + "/*", SECRET_KEY_RING_BY_KEY_ID); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/" - + KeychainContract.PATH_BY_EMAILS + "/*", SECRET_KEY_RING_BY_EMAILS); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/" - + KeychainContract.PATH_BY_EMAILS, SECRET_KEY_RING_BY_EMAILS); // without emails - // specified - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/" - + KeychainContract.PATH_BY_LIKE_EMAIL + "/*", SECRET_KEY_RING_BY_LIKE_EMAIL); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_SECRET, SECRET_KEY_RING); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_SECRET + "/#", SECRET_KEY_RING_BY_ROW_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_MASTER_KEY_ID + + "/*", SECRET_KEY_RING_BY_MASTER_KEY_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_KEY_ID + "/*", + SECRET_KEY_RING_BY_KEY_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_EMAILS + "/*", + SECRET_KEY_RING_BY_EMAILS); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_EMAILS, + SECRET_KEY_RING_BY_EMAILS); // without emails + // specified + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_LIKE_EMAIL + "/*", + SECRET_KEY_RING_BY_LIKE_EMAIL); /** * secret keys @@ -184,10 +200,12 @@ public class KeychainProvider extends ContentProvider { * key_rings/secret/#/keys/# * */ - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET - + "/#/" + KeychainContract.PATH_KEYS, SECRET_KEY_RING_KEY); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET - + "/#/" + KeychainContract.PATH_KEYS + "/#", SECRET_KEY_RING_KEY_BY_ROW_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_SECRET + "/#/" + KeychainContract.PATH_KEYS, + SECRET_KEY_RING_KEY); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_SECRET + "/#/" + KeychainContract.PATH_KEYS + "/#", + SECRET_KEY_RING_KEY_BY_ROW_ID); /** * secret user ids @@ -197,10 +215,12 @@ public class KeychainProvider extends ContentProvider { * key_rings/secret/#/user_ids/# * */ - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET - + "/#/" + KeychainContract.PATH_USER_IDS, SECRET_KEY_RING_USER_ID); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET - + "/#/" + KeychainContract.PATH_USER_IDS + "/#", SECRET_KEY_RING_USER_ID_BY_ROW_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_SECRET + "/#/" + KeychainContract.PATH_USER_IDS, + SECRET_KEY_RING_USER_ID); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + + KeychainContract.PATH_SECRET + "/#/" + KeychainContract.PATH_USER_IDS + "/#", + SECRET_KEY_RING_USER_ID_BY_ROW_ID); /** * data stream @@ -656,6 +676,7 @@ public class KeychainProvider extends ContentProvider { // notify of changes in db getContext().getContentResolver().notifyChange(uri, null); + sendBroadcastDatabaseChange(); return rowUri; } @@ -704,6 +725,7 @@ public class KeychainProvider extends ContentProvider { // notify of changes in db getContext().getContentResolver().notifyChange(uri, null); + sendBroadcastDatabaseChange(); return count; } @@ -761,6 +783,7 @@ public class KeychainProvider extends ContentProvider { // notify of changes in db getContext().getContentResolver().notifyChange(uri, null); + sendBroadcastDatabaseChange(); return count; } @@ -849,4 +872,14 @@ public class KeychainProvider extends ContentProvider { File file = new File(getContext().getFilesDir().getAbsolutePath(), fileName); return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } + + /** + * This broadcast is send system wide to inform other application that a keyring was inserted, + * updated, or deleted + */ + private void sendBroadcastDatabaseChange() { + Intent intent = new Intent(); + intent.setAction(ACTION_BROADCAST_DATABASE_CHANGE); + getContext().sendBroadcast(intent, Constants.PERMISSION_ACCESS_API); + } } diff --git a/README.md b/README.md index c32c5c3e4..5bdf080df 100644 --- a/README.md +++ b/README.md @@ -66,14 +66,15 @@ See http://docs.oseems.com/general/application/eclipse/fix-gc-overhead-limit-exc Android primitives to exchange data: Intent, Intent with return values, Send (also an Intent), Content Provider, AIDL -## Permission +## Possible Permissions * ACCESS_API: Encrypt/Sign/Decrypt/Create keys without user interaction (intents, remote service), Read key information (not the actual keys)(content provider) * ACCESS_KEYS: get and import actual public and secret keys (remote service) -## Intents +## Without Permissions -### Without permission +### Intents +All Intents start with org.sufficientlysecure.keychain.action. * android.intent.action.VIEW connected to .gpg and .asc files: Import Key and Decrypt * android.intent.action.SEND connected to all mime types (text/plain and every binary data like files and images): Encrypt and Decrypt @@ -92,7 +93,9 @@ Android primitives to exchange data: Intent, Intent with return values, Send (al * DECRYPT * DECRYPT_FILE -### With permission ACCESS_API +## With permission ACCESS_API + +### Intents * CREATE_KEYRING * ENCRYPT_AND_RETURN @@ -101,7 +104,11 @@ Android primitives to exchange data: Intent, Intent with return values, Send (al * DECRYPT_AND_RETURN * DECRYPT_STREAM_AND_RETURN -## Content Provider +### Broadcast Receiver +On change of database the following broadcast is send. +* DATABASE_CHANGE + +### Content Provider * The whole content provider requires a permission (only read) * Don't give out blobs (keys can be accessed by ACCESS_KEYS via remote service) @@ -109,11 +116,13 @@ Android primitives to exchange data: Intent, Intent with return values, Send (al * Look at android:grantUriPermissions especially for ApgServiceBlobProvider * Only give out android:readPermission -## ApgApiService (Remote Service) -* ACCESS_API +### ApgApiService (Remote Service) +AIDL service -## ApgKeyService (Remote Service) -* ACCESS_KEYS +## With permission ACCESS_KEYS + +### ApgKeyService (Remote Service) +AIDL service to access actual private keyring objects # Licenses OpenPGP Kechain is licensed under Apache License v2.