New broadcast on database change to inform other apps

This commit is contained in:
Dominik Schürmann 2013-01-18 23:51:44 +01:00
parent d599d26bbd
commit 4177f7159c
3 changed files with 109 additions and 60 deletions

View file

@ -235,11 +235,18 @@ public class KeychainContentProviderHelper {
* @param keyId * @param keyId
* @return user id * @return user id
*/ */
public String getUserId(long keyId) { public String getUserId(long keyId, boolean secretKeyrings) {
String userId = null; String userId = null;
try { try {
Uri contentUri = ContentUris.withAppendedId(CONTENT_URI_SECRET_KEY_RING_BY_KEY_ID, Uri contentUri = null;
keyId); 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" }, Cursor c = mContext.getContentResolver().query(contentUri, new String[] { "user_id" },
null, null, null); null, null, null);
if (c != null && c.moveToFirst()) { if (c != null && c.moveToFirst()) {

View file

@ -35,6 +35,7 @@ import org.sufficientlysecure.keychain.util.Log;
import android.content.ContentProvider; import android.content.ContentProvider;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Intent;
import android.content.UriMatcher; import android.content.UriMatcher;
import android.database.Cursor; import android.database.Cursor;
import android.database.DatabaseUtils; import android.database.DatabaseUtils;
@ -47,6 +48,9 @@ import android.provider.BaseColumns;
import android.text.TextUtils; import android.text.TextUtils;
public class KeychainProvider extends ContentProvider { 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 = 101;
private static final int PUBLIC_KEY_RING_BY_ROW_ID = 102; private static final int PUBLIC_KEY_RING_BY_ROW_ID = 102;
private static final int PUBLIC_KEY_RING_BY_MASTER_KEY_ID = 103; private static final int PUBLIC_KEY_RING_BY_MASTER_KEY_ID = 103;
@ -104,22 +108,26 @@ public class KeychainProvider extends ContentProvider {
* key_rings/public/like_email/_ * key_rings/public/like_email/_
* </pre> * </pre>
*/ */
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC, matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
PUBLIC_KEY_RING); + KeychainContract.PATH_PUBLIC, PUBLIC_KEY_RING);
matcher.addURI(authority, matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/#", + KeychainContract.PATH_PUBLIC + "/#", PUBLIC_KEY_RING_BY_ROW_ID);
PUBLIC_KEY_RING_BY_ROW_ID); matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_MASTER_KEY_ID
+ KeychainContract.PATH_BY_MASTER_KEY_ID + "/*", PUBLIC_KEY_RING_BY_MASTER_KEY_ID); + "/*", PUBLIC_KEY_RING_BY_MASTER_KEY_ID);
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/" matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+ KeychainContract.PATH_BY_KEY_ID + "/*", PUBLIC_KEY_RING_BY_KEY_ID); + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_KEY_ID + "/*",
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/" PUBLIC_KEY_RING_BY_KEY_ID);
+ KeychainContract.PATH_BY_EMAILS + "/*", PUBLIC_KEY_RING_BY_EMAILS); matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_EMAILS + "/*",
+ KeychainContract.PATH_BY_EMAILS, PUBLIC_KEY_RING_BY_EMAILS); // without emails PUBLIC_KEY_RING_BY_EMAILS);
// specified matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_PUBLIC + "/" + KeychainContract.PATH_BY_EMAILS,
+ KeychainContract.PATH_BY_LIKE_EMAIL + "/*", PUBLIC_KEY_RING_BY_LIKE_EMAIL); 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 * public keys
@ -129,10 +137,12 @@ public class KeychainProvider extends ContentProvider {
* key_rings/public/#/keys/# * key_rings/public/#/keys/#
* </pre> * </pre>
*/ */
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+ "/#/" + KeychainContract.PATH_KEYS, PUBLIC_KEY_RING_KEY); + KeychainContract.PATH_PUBLIC + "/#/" + KeychainContract.PATH_KEYS,
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC PUBLIC_KEY_RING_KEY);
+ "/#/" + 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_BY_ROW_ID);
/** /**
* public user ids * public user ids
@ -142,10 +152,12 @@ public class KeychainProvider extends ContentProvider {
* key_rings/public/#/user_ids/# * key_rings/public/#/user_ids/#
* </pre> * </pre>
*/ */
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+ "/#/" + KeychainContract.PATH_USER_IDS, PUBLIC_KEY_RING_USER_ID); + KeychainContract.PATH_PUBLIC + "/#/" + KeychainContract.PATH_USER_IDS,
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_PUBLIC PUBLIC_KEY_RING_USER_ID);
+ "/#/" + 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_BY_ROW_ID);
/** /**
* secret key rings * secret key rings
@ -159,22 +171,26 @@ public class KeychainProvider extends ContentProvider {
* key_rings/secret/like_email/_ * key_rings/secret/like_email/_
* </pre> * </pre>
*/ */
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET, matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
SECRET_KEY_RING); + KeychainContract.PATH_SECRET, SECRET_KEY_RING);
matcher.addURI(authority, matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/#", + KeychainContract.PATH_SECRET + "/#", SECRET_KEY_RING_BY_ROW_ID);
SECRET_KEY_RING_BY_ROW_ID); matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_MASTER_KEY_ID
+ KeychainContract.PATH_BY_MASTER_KEY_ID + "/*", SECRET_KEY_RING_BY_MASTER_KEY_ID); + "/*", SECRET_KEY_RING_BY_MASTER_KEY_ID);
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/" matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+ KeychainContract.PATH_BY_KEY_ID + "/*", SECRET_KEY_RING_BY_KEY_ID); + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_KEY_ID + "/*",
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/" SECRET_KEY_RING_BY_KEY_ID);
+ KeychainContract.PATH_BY_EMAILS + "/*", SECRET_KEY_RING_BY_EMAILS); matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_EMAILS + "/*",
+ KeychainContract.PATH_BY_EMAILS, SECRET_KEY_RING_BY_EMAILS); // without emails SECRET_KEY_RING_BY_EMAILS);
// specified matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_SECRET + "/" + KeychainContract.PATH_BY_EMAILS,
+ KeychainContract.PATH_BY_LIKE_EMAIL + "/*", SECRET_KEY_RING_BY_LIKE_EMAIL); 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 * secret keys
@ -184,10 +200,12 @@ public class KeychainProvider extends ContentProvider {
* key_rings/secret/#/keys/# * key_rings/secret/#/keys/#
* </pre> * </pre>
*/ */
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+ "/#/" + KeychainContract.PATH_KEYS, SECRET_KEY_RING_KEY); + KeychainContract.PATH_SECRET + "/#/" + KeychainContract.PATH_KEYS,
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET SECRET_KEY_RING_KEY);
+ "/#/" + 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_BY_ROW_ID);
/** /**
* secret user ids * secret user ids
@ -197,10 +215,12 @@ public class KeychainProvider extends ContentProvider {
* key_rings/secret/#/user_ids/# * key_rings/secret/#/user_ids/#
* </pre> * </pre>
*/ */
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+ "/#/" + KeychainContract.PATH_USER_IDS, SECRET_KEY_RING_USER_ID); + KeychainContract.PATH_SECRET + "/#/" + KeychainContract.PATH_USER_IDS,
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_SECRET SECRET_KEY_RING_USER_ID);
+ "/#/" + 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_BY_ROW_ID);
/** /**
* data stream * data stream
@ -656,6 +676,7 @@ public class KeychainProvider extends ContentProvider {
// notify of changes in db // notify of changes in db
getContext().getContentResolver().notifyChange(uri, null); getContext().getContentResolver().notifyChange(uri, null);
sendBroadcastDatabaseChange();
return rowUri; return rowUri;
} }
@ -704,6 +725,7 @@ public class KeychainProvider extends ContentProvider {
// notify of changes in db // notify of changes in db
getContext().getContentResolver().notifyChange(uri, null); getContext().getContentResolver().notifyChange(uri, null);
sendBroadcastDatabaseChange();
return count; return count;
} }
@ -761,6 +783,7 @@ public class KeychainProvider extends ContentProvider {
// notify of changes in db // notify of changes in db
getContext().getContentResolver().notifyChange(uri, null); getContext().getContentResolver().notifyChange(uri, null);
sendBroadcastDatabaseChange();
return count; return count;
} }
@ -849,4 +872,14 @@ public class KeychainProvider extends ContentProvider {
File file = new File(getContext().getFilesDir().getAbsolutePath(), fileName); File file = new File(getContext().getFilesDir().getAbsolutePath(), fileName);
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); 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);
}
} }

View file

@ -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 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_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) * 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.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 * 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
* DECRYPT_FILE * DECRYPT_FILE
### With permission ACCESS_API ## With permission ACCESS_API
### Intents
* CREATE_KEYRING * CREATE_KEYRING
* ENCRYPT_AND_RETURN * ENCRYPT_AND_RETURN
@ -101,7 +104,11 @@ Android primitives to exchange data: Intent, Intent with return values, Send (al
* DECRYPT_AND_RETURN * DECRYPT_AND_RETURN
* DECRYPT_STREAM_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) * The whole content provider requires a permission (only read)
* Don't give out blobs (keys can be accessed by ACCESS_KEYS via remote service) * 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 * Look at android:grantUriPermissions especially for ApgServiceBlobProvider
* Only give out android:readPermission * Only give out android:readPermission
## ApgApiService (Remote Service) ### ApgApiService (Remote Service)
* ACCESS_API AIDL service
## ApgKeyService (Remote Service) ## With permission ACCESS_KEYS
* ACCESS_KEYS
### ApgKeyService (Remote Service)
AIDL service to access actual private keyring objects
# Licenses # Licenses
OpenPGP Kechain is licensed under Apache License v2. OpenPGP Kechain is licensed under Apache License v2.