introduced keyserver sync adapter
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user