introduced keyserver sync adapter

This commit is contained in:
Adithya Abraham Philip
2015-07-27 14:10:26 +05:30
parent e643e098e2
commit 1ef6f883e3
14 changed files with 456 additions and 26 deletions

View File

@@ -51,6 +51,11 @@ public class KeychainContract {
String EXPIRY = "expiry";
}
interface UpdatedKeysColumns {
String MASTER_KEY_ID = "master_key_id"; // not a database id
String LAST_UPDATED = "last_updated"; // time since epoch in seconds
}
interface UserPacketsColumns {
String MASTER_KEY_ID = "master_key_id"; // foreign key to key_rings._ID
String TYPE = "type"; // not a database id
@@ -97,6 +102,8 @@ public class KeychainContract {
public static final String BASE_KEY_RINGS = "key_rings";
public static final String BASE_UPDATED_KEYS = "updated_keys";
public static final String PATH_UNIFIED = "unified";
public static final String PATH_FIND = "find";
@@ -234,6 +241,16 @@ public class KeychainContract {
}
public static class UpdatedKeys implements UpdatedKeysColumns, BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_UPDATED_KEYS).build();
public static final String CONTENT_TYPE
= "vnd.android.cursor.dir/vnd.org.sufficientlysecure.keychain.provider.updated_keys";
public static final String CONTENT_ITEM_TYPE
= "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.provider.updated_keys";
}
public static class UserPackets implements UserPacketsColumns, BaseColumns {
public static final String VERIFIED = "verified";
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()

View File

@@ -34,6 +34,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.CertsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeysColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPacketsColumns;
import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity;
import org.sufficientlysecure.keychain.util.Log;
@@ -53,7 +54,7 @@ import java.io.IOException;
*/
public class KeychainDatabase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "openkeychain.db";
private static final int DATABASE_VERSION = 11;
private static final int DATABASE_VERSION = 12;
static Boolean apgHack = false;
private Context mContext;
@@ -61,6 +62,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
String KEY_RINGS_PUBLIC = "keyrings_public";
String KEY_RINGS_SECRET = "keyrings_secret";
String KEYS = "keys";
String UPDATED_KEYS = "updated_keys";
String USER_PACKETS = "user_packets";
String CERTS = "certs";
String API_APPS = "api_apps";
@@ -144,6 +146,14 @@ public class KeychainDatabase extends SQLiteOpenHelper {
+ Tables.USER_PACKETS + "(" + UserPacketsColumns.MASTER_KEY_ID + ", " + UserPacketsColumns.RANK + ") ON DELETE CASCADE"
+ ")";
private static final String CREATE_UPDATE_KEYS =
"CREATE TABLE IF NOT EXISTS " + Tables.UPDATED_KEYS + " ("
+ UpdatedKeysColumns.MASTER_KEY_ID + " INTEGER PRIMARY KEY, "
+ UpdatedKeysColumns.LAST_UPDATED + " INTEGER, "
+ "FOREIGN KEY(" + UpdatedKeysColumns.MASTER_KEY_ID + ") REFERENCES "
+ Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
+ ")";
private static final String CREATE_API_APPS =
"CREATE TABLE IF NOT EXISTS " + Tables.API_APPS + " ("
+ BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
@@ -206,6 +216,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
db.execSQL(CREATE_KEYS);
db.execSQL(CREATE_USER_PACKETS);
db.execSQL(CREATE_CERTS);
db.execSQL(CREATE_UPDATE_KEYS);
db.execSQL(CREATE_API_APPS);
db.execSQL(CREATE_API_APPS_ACCOUNTS);
db.execSQL(CREATE_API_APPS_ALLOWED_KEYS);
@@ -278,8 +289,11 @@ public class KeychainDatabase extends SQLiteOpenHelper {
// fix problems in database, see #1402 for details
// https://github.com/open-keychain/open-keychain/issues/1402
db.execSQL("DELETE FROM api_accounts WHERE key_id BETWEEN 0 AND 3");
case 12:
db.execSQL(CREATE_UPDATE_KEYS);
if (oldVersion == 10) {
// no consolidate if we are updating from 10, we're just here for the api_accounts fix
// no consolidate if we are updating from 10, we're just here for
// the api_accounts fix and the new update keys table
return;
}

View File

@@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPacketsColumns;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
@@ -72,6 +73,9 @@ public class KeychainProvider extends ContentProvider {
private static final int KEY_RINGS_FIND_BY_EMAIL = 400;
private static final int KEY_RINGS_FIND_BY_SUBKEY = 401;
private static final int UPDATED_KEYS = 500;
private static final int UPDATED_KEYS_SPECIFIC = 501;
protected UriMatcher mUriMatcher;
/**
@@ -179,6 +183,12 @@ public class KeychainProvider extends ContentProvider {
matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/"
+ KeychainContract.PATH_ALLOWED_KEYS, API_ALLOWED_KEYS);
/**
* to access table containing last updated dates of keys
*/
matcher.addURI(authority, KeychainContract.BASE_UPDATED_KEYS, UPDATED_KEYS);
matcher.addURI(authority, KeychainContract.BASE_UPDATED_KEYS + "/*", UPDATED_KEYS_SPECIFIC);
return matcher;
}
@@ -218,6 +228,11 @@ public class KeychainProvider extends ContentProvider {
case KEY_RING_SECRET:
return KeyRings.CONTENT_ITEM_TYPE;
case UPDATED_KEYS:
return UpdatedKeys.CONTENT_TYPE;
case UPDATED_KEYS_SPECIFIC:
return UpdatedKeys.CONTENT_ITEM_TYPE;
case API_APPS:
return ApiApps.CONTENT_TYPE;
@@ -606,6 +621,22 @@ public class KeychainProvider extends ContentProvider {
break;
}
case UPDATED_KEYS:
case UPDATED_KEYS_SPECIFIC: {
HashMap<String, String> projectionMap = new HashMap<>();
qb.setTables(Tables.UPDATED_KEYS);
projectionMap.put(UpdatedKeys.MASTER_KEY_ID, Tables.UPDATED_KEYS + "."
+ UpdatedKeys.MASTER_KEY_ID);
projectionMap.put(UpdatedKeys.LAST_UPDATED, Tables.UPDATED_KEYS + "."
+ UpdatedKeys.LAST_UPDATED);
qb.setProjectionMap(projectionMap);
if (match == UPDATED_KEYS_SPECIFIC) {
qb.appendWhere(UpdatedKeys.MASTER_KEY_ID + " = ");
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
}
break;
}
case API_APPS: {
qb.setTables(Tables.API_APPS);
@@ -726,6 +757,12 @@ public class KeychainProvider extends ContentProvider {
keyId = values.getAsLong(Certs.MASTER_KEY_ID);
break;
}
case UPDATED_KEYS: {
long updatedKeyId = db.replace(Tables.UPDATED_KEYS, null, values);
rowUri = UpdatedKeys.CONTENT_URI.buildUpon().appendPath("" + updatedKeyId)
.build();
break;
}
case API_APPS: {
db.insertOrThrow(Tables.API_APPS, null, values);
break;

View File

@@ -59,6 +59,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys;
import org.sufficientlysecure.keychain.remote.AccountSettings;
import org.sufficientlysecure.keychain.remote.AppSettings;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@@ -82,6 +83,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* This class contains high level methods for database access. Despite its
@@ -685,6 +687,41 @@ public class ProviderHelper {
mIndent -= 1;
}
// before deleting key, retrieve it's last updated time
final int INDEX_MASTER_KEY_ID = 0;
final int INDEX_LAST_UPDATED = 1;
Cursor lastUpdatedCursor = mContentResolver.query(
UpdatedKeys.CONTENT_URI,
new String[]{
UpdatedKeys.MASTER_KEY_ID,
UpdatedKeys.LAST_UPDATED
},
UpdatedKeys.MASTER_KEY_ID + " = ?",
new String[]{"" + masterKeyId},
null
);
ContentValues lastUpdatedEntry = null;
if (lastUpdatedCursor.moveToNext()) {
lastUpdatedEntry = new ContentValues(2);
lastUpdatedEntry.put(UpdatedKeys.MASTER_KEY_ID,
lastUpdatedCursor.getLong(INDEX_MASTER_KEY_ID));
lastUpdatedEntry.put(UpdatedKeys.LAST_UPDATED,
lastUpdatedCursor.getLong(INDEX_LAST_UPDATED));
Log.e("PHILIP", "cv: " + lastUpdatedEntry + " actual: " + masterKeyId);
}
lastUpdatedCursor.close();
if (lastUpdatedEntry != null) {
// there was an entry to re-insert
// this operation must happen after the new key is inserted
operations.add(
ContentProviderOperation
.newInsert(UpdatedKeys.CONTENT_URI)
.withValues(lastUpdatedEntry)
.build()
);
}
try {
// delete old version of this keyRing, which also deletes all keys and userIds on cascade
int deleted = mContentResolver.delete(
@@ -1239,6 +1276,28 @@ public class ProviderHelper {
}
// 2. wipe database (IT'S DANGEROUS)
// first, backup our list of updated key times
ArrayList<ContentValues> updatedKeysValues = new ArrayList<>();
final int INDEX_MASTER_KEY_ID = 0;
final int INDEX_LAST_UPDATED = 1;
Cursor lastUpdatedCursor = mContentResolver.query(
UpdatedKeys.CONTENT_URI,
new String[]{
UpdatedKeys.MASTER_KEY_ID,
UpdatedKeys.LAST_UPDATED
},
null, null, null);
while (lastUpdatedCursor.moveToNext()) {
ContentValues values = new ContentValues();
values.put(UpdatedKeys.MASTER_KEY_ID,
lastUpdatedCursor.getLong(INDEX_MASTER_KEY_ID));
values.put(UpdatedKeys.LAST_UPDATED,
lastUpdatedCursor.getLong(INDEX_LAST_UPDATED));
updatedKeysValues.add(values);
}
lastUpdatedCursor.close();
log.add(LogType.MSG_CON_DB_CLEAR, indent);
mContentResolver.delete(KeyRings.buildUnifiedKeyRingsUri(), null, null);
@@ -1288,6 +1347,10 @@ public class ProviderHelper {
new ProgressFixedScaler(progress, 25, 99, 100, R.string.progress_con_reimport))
.serialKeyRingImport(itPublics, numPublics, null, null);
log.add(result, indent);
// re-insert our backed up list of updated key times
// TODO: can this cause issues in case a public key re-import failed?
mContentResolver.bulkInsert(UpdatedKeys.CONTENT_URI,
updatedKeysValues.toArray(new ContentValues[updatedKeysValues.size()]));
} else {
log.add(LogType.MSG_CON_REIMPORT_PUBLIC_SKIP, indent);
}
@@ -1397,6 +1460,14 @@ public class ProviderHelper {
return getKeyRingAsArmoredString(data);
}
public Uri renewKeyLastUpdatedTime(long masterKeyId, long time, TimeUnit timeUnit) {
ContentValues values = new ContentValues();
values.put(UpdatedKeys.MASTER_KEY_ID, masterKeyId);
values.put(UpdatedKeys.LAST_UPDATED, timeUnit.toSeconds(time));
return mContentResolver.insert(UpdatedKeys.CONTENT_URI, values);
}
public ArrayList<String> getRegisteredApiApps() {
Cursor cursor = mContentResolver.query(ApiApps.CONTENT_URI, null, null, null, null);