added content provider again and read permission to grab key details

This commit is contained in:
Thialfihar 2010-06-02 14:01:18 +00:00
parent 1d023b0372
commit 7193edbba2
5 changed files with 385 additions and 56 deletions

View File

@ -128,9 +128,20 @@
android:label="@string/title_preferences"
android:configChanges="keyboardHidden|orientation|keyboard"/>
<provider
android:readPermission="org.thialfihar.android.apg.permission.READ_KEY_DETAILS"
android:name="org.thialfihar.android.apg.provider.DataProvider"
android:authorities="org.thialfihar.android.apg.provider"/>
</application>
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="5" />
<uses-permission android:name="com.google.android.providers.gmail.permission.READ_GMAIL" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
</manifest>
<permission android:name="org.thialfihar.android.apg.permission.READ_KEY_DETAILS"
android:protectionLevel="dangerous"
android:label="@string/permission_read_key_details_label"
android:description="@string/permission_read_key_details_description"/>
<uses-permission android:name="com.google.android.providers.gmail.permission.READ_GMAIL" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>

View File

@ -239,5 +239,9 @@
<string name="progress_decompressingData">decompressing data...</string>
<string name="progress_verifyingIntegrity">verifying integrity...</string>
<!-- permission strings -->
<string name="permission_read_key_details_label">Read key details from APG.</string>
<string name="permission_read_key_details_description">Read of public and secret keys stored in APG, such as key ID and user IDs. The keys themselves can NOT be read.</string>
</resources>

View File

@ -44,7 +44,6 @@ public class SelectSecretKeyListActivity extends BaseActivity {
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Intent data = new Intent();
data.putExtra(Apg.EXTRA_KEY_ID, id);
data.putExtra(Apg.EXTRA_USER_ID, Apg.getMainUserId(id, Id.database.type_secret));
setResult(RESULT_OK, data);
finish();
}

View File

@ -0,0 +1,315 @@
/*
* 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.util.HashMap;
import org.thialfihar.android.apg.Id;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
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_RINGS = 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_KEYS = 111;
private static final int PUBLIC_KEY_RING_KEY_RANK = 112;
private static final int PUBLIC_KEY_RING_USER_IDS = 121;
private static final int PUBLIC_KEY_RING_USER_ID_RANK = 122;
private static final int SECRET_KEY_RINGS = 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_KEYS = 211;
private static final int SECRET_KEY_RING_KEY_RANK = 212;
private static final int SECRET_KEY_RING_USER_IDS = 221;
private static final int SECRET_KEY_RING_USER_ID_RANK = 222;
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 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/*/keys", PUBLIC_KEY_RING_KEYS);
mUriMatcher.addURI(AUTHORITY, "key_rings/public/*/keys/#", PUBLIC_KEY_RING_KEY_RANK);
mUriMatcher.addURI(AUTHORITY, "key_rings/public/*/user_ids", PUBLIC_KEY_RING_USER_IDS);
mUriMatcher.addURI(AUTHORITY, "key_rings/public/*/user_ids/#", PUBLIC_KEY_RING_USER_ID_RANK);
mUriMatcher.addURI(AUTHORITY, "key_rings/public", PUBLIC_KEY_RINGS);
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/*/keys", SECRET_KEY_RING_KEYS);
mUriMatcher.addURI(AUTHORITY, "key_rings/secret/*/keys/#", SECRET_KEY_RING_KEY_RANK);
mUriMatcher.addURI(AUTHORITY, "key_rings/secret/*/user_ids", SECRET_KEY_RING_USER_IDS);
mUriMatcher.addURI(AUTHORITY, "key_rings/secret/*/user_ids/#", SECRET_KEY_RING_USER_ID_RANK);
mUriMatcher.addURI(AUTHORITY, "key_rings/secret", SECRET_KEY_RINGS);
mUriMatcher.addURI(AUTHORITY, "key_rings/secret/*", SECRET_KEY_RING_ID);
}
@Override
public boolean onCreate() {
mDb = new Database(getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
HashMap<String, String> projectionMap = new HashMap<String, String>();
int match = mUriMatcher.match(uri);
int type;
switch (match) {
case PUBLIC_KEY_RINGS:
case PUBLIC_KEY_RING_ID:
case PUBLIC_KEY_RING_BY_KEY_ID:
case PUBLIC_KEY_RING_KEYS:
case PUBLIC_KEY_RING_KEY_RANK:
case PUBLIC_KEY_RING_USER_IDS:
case PUBLIC_KEY_RING_USER_ID_RANK:
type = Id.database.type_public;
break;
case SECRET_KEY_RINGS:
case SECRET_KEY_RING_ID:
case SECRET_KEY_RING_BY_KEY_ID:
case SECRET_KEY_RING_KEYS:
case SECRET_KEY_RING_KEY_RANK:
case SECRET_KEY_RING_USER_IDS:
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_RINGS:
case SECRET_KEY_RINGS: {
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(MASTER_KEY_ID,
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID);
projectionMap.put(USER_ID,
UserIds.TABLE_NAME + "." + UserIds.USER_ID);
break;
}
case PUBLIC_KEY_RING_ID:
case SECRET_KEY_RING_ID: {
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(MASTER_KEY_ID,
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID);
projectionMap.put(USER_ID,
UserIds.TABLE_NAME + "." + UserIds.USER_ID);
qb.appendWhere(" AND " +
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(2));
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(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;
}
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_RINGS:
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_KEYS:
return PUBLIC_KEY_CONTENT_DIR_TYPE;
case PUBLIC_KEY_RING_KEY_RANK:
return PUBLIC_KEY_CONTENT_ITEM_TYPE;
case PUBLIC_KEY_RING_USER_IDS:
return USER_ID_CONTENT_DIR_TYPE;
case PUBLIC_KEY_RING_USER_ID_RANK:
return USER_ID_CONTENT_ITEM_TYPE;
case SECRET_KEY_RINGS:
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_KEYS:
return SECRET_KEY_CONTENT_DIR_TYPE;
case SECRET_KEY_RING_KEY_RANK:
return SECRET_KEY_CONTENT_ITEM_TYPE;
case SECRET_KEY_RING_USER_IDS:
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;
}
}

View File

@ -389,9 +389,9 @@ public class Database extends SQLiteOpenHelper {
seenIdsStr += id;
}
mDb.delete(UserIds.TABLE_NAME,
UserIds.KEY_ID + " = ? AND " +
UserIds._ID + " NOT IN (" + seenIdsStr + ")",
new String[] { "" + rowId });
UserIds.KEY_ID + " = ? AND " +
UserIds._ID + " NOT IN (" + seenIdsStr + ")",
new String[] { "" + rowId });
return (int)rowId;
}
@ -414,17 +414,17 @@ public class Database extends SQLiteOpenHelper {
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);
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 });
KeyRings._ID + " = ?", new String[] { "" + rowId });
mStatus = Id.return_value.updated;
} else {
rowId = mDb.insert(KeyRings.TABLE_NAME, KeyRings.WHO_ID, values);
@ -440,17 +440,17 @@ public class Database extends SQLiteOpenHelper {
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);
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 });
Keys._ID + " = ?", new String[] { "" + rowId });
} else {
rowId = mDb.insert(Keys.TABLE_NAME, Keys.KEY_DATA, values);
}
@ -464,12 +464,12 @@ public class Database extends SQLiteOpenHelper {
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);
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);
@ -488,12 +488,12 @@ public class Database extends SQLiteOpenHelper {
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);
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()) {
@ -522,16 +522,16 @@ public class Database extends SQLiteOpenHelper {
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);
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()) {
@ -547,12 +547,12 @@ public class Database extends SQLiteOpenHelper {
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);
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);
@ -568,13 +568,13 @@ public class Database extends SQLiteOpenHelper {
public void deleteKeyRing(int keyRingId) {
mDb.beginTransaction();
mDb.delete(KeyRings.TABLE_NAME,
KeyRings._ID + " = ?", new String[] { "" + keyRingId });
KeyRings._ID + " = ?", new String[] { "" + keyRingId });
Cursor c = mDb.query(Keys.TABLE_NAME, new String[] { Keys._ID },
Keys.KEY_RING_ID + " = ?",
new String[] {
"" + keyRingId,
},
Keys.KEY_RING_ID + " = ?",
new String[] {
"" + keyRingId,
},
null, null, null);
if (c != null && c.moveToFirst()) {
do {
@ -593,10 +593,10 @@ public class Database extends SQLiteOpenHelper {
private void deleteKey(int keyId) {
mDb.delete(Keys.TABLE_NAME,
Keys._ID + " = ?", new String[] { "" + keyId });
Keys._ID + " = ?", new String[] { "" + keyId });
mDb.delete(UserIds.TABLE_NAME,
UserIds.KEY_ID + " = ?", new String[] { "" + keyId });
UserIds.KEY_ID + " = ?", new String[] { "" + keyId });
}
public SQLiteDatabase db() {