Update AGP to 7.4.2, update SqlDelight to 1.4.2

The adaptations to SqlDelight 1.4.2 leave the type namings *extremely*
messy. But it works and is as semantically equivalent as I could make
it.
This commit is contained in:
Vincent Breitmoser
2024-01-10 17:02:03 +01:00
parent 0caeca0b66
commit 5d84bd8387
104 changed files with 1141 additions and 1742 deletions

5
.gitignore vendored
View File

@@ -37,4 +37,7 @@ fastlane/screenshots
fastlane/test_output fastlane/test_output
# omit for now: # omit for now:
fastlane/Appfile fastlane/Appfile
OpenKeychain/release
OpenKeychain/google

View File

@@ -1,5 +1,8 @@
apply plugin: 'com.android.application' plugins {
apply plugin: 'com.squareup.sqldelight' id 'com.android.application'
id 'kotlin-android'
id 'com.squareup.sqldelight'
}
dependencies { dependencies {
// from local Android SDK // from local Android SDK
@@ -20,6 +23,7 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.9' implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.9'
implementation 'org.apache.james:apache-mime4j-core:0.8.1' implementation 'org.apache.james:apache-mime4j-core:0.8.1'
implementation 'org.apache.james:apache-mime4j-dom:0.8.1' implementation 'org.apache.james:apache-mime4j-dom:0.8.1'
implementation "com.squareup.sqldelight:android-driver:1.5.4"
// UI // UI
implementation 'org.sufficientlysecure:html-textview:3.1' implementation 'org.sufficientlysecure:html-textview:3.1'
@@ -86,6 +90,7 @@ dependencies {
android { android {
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
namespace 'org.sufficientlysecure.keychain'
defaultConfig { defaultConfig {
minSdkVersion 15 minSdkVersion 15

View File

@@ -23,17 +23,15 @@ import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import android.content.Context;
import androidx.sqlite.db.SupportSQLiteDatabase; import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.sqlite.db.SupportSQLiteOpenHelper; import androidx.sqlite.db.SupportSQLiteOpenHelper;
import androidx.sqlite.db.SupportSQLiteOpenHelper.Callback; import androidx.sqlite.db.SupportSQLiteOpenHelper.Callback;
import androidx.sqlite.db.SupportSQLiteOpenHelper.Configuration; import androidx.sqlite.db.SupportSQLiteOpenHelper.Configuration;
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory; import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory;
import android.content.Context; import com.squareup.sqldelight.android.AndroidSqliteDriver;
import android.database.Cursor; import org.sufficientlysecure.keychain.model.CustomColumnAdapters;
import android.database.SQLException;
import android.database.sqlite.SQLiteException;
import org.sufficientlysecure.keychain.daos.LocalSecretKeyStorage;
import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Preferences;
import timber.log.Timber; import timber.log.Timber;
@@ -41,15 +39,18 @@ import timber.log.Timber;
/** /**
* SQLite Datatypes (from http://www.sqlite.org/datatype3.html) * SQLite Datatypes (from http://www.sqlite.org/datatype3.html)
* - NULL. The value is a NULL value. * - NULL. The value is a NULL value.
* - INTEGER. The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude of the value. * - INTEGER. The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending on the
* magnitude of the value.
* - REAL. The value is a floating point value, stored as an 8-byte IEEE floating point number. * - REAL. The value is a floating point value, stored as an 8-byte IEEE floating point number.
* - TEXT. The value is a text string, stored using the database encoding (UTF-8, UTF-16BE or UTF-16LE). * - TEXT. The value is a text string, stored using the database encoding (UTF-8, UTF-16BE or
* UTF-16LE).
* - BLOB. The value is a blob of data, stored exactly as it was input. * - BLOB. The value is a blob of data, stored exactly as it was input.
*/ */
public class KeychainDatabase { public class KeychainDatabase {
private static final String DATABASE_NAME = "openkeychain.db"; private static final String DATABASE_NAME = "openkeychain.db";
private static final int DATABASE_VERSION = 34; private static final int DATABASE_VERSION = 35;
private final SupportSQLiteOpenHelper supportSQLiteOpenHelper; private final SupportSQLiteOpenHelper supportSQLiteOpenHelper;
private final Database sqldelightDatabase;
private static KeychainDatabase sInstance; private static KeychainDatabase sInstance;
@@ -71,12 +72,15 @@ public class KeychainDatabase {
} }
@Override @Override
public void onUpgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) { public void onUpgrade(SupportSQLiteDatabase db, int oldVersion,
KeychainDatabase.this.onUpgrade(db, context, oldVersion, newVersion); int newVersion) {
KeychainDatabase.this.onUpgrade(db, context, oldVersion,
newVersion);
} }
@Override @Override
public void onDowngrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) { public void onDowngrade(SupportSQLiteDatabase db,
int oldVersion, int newVersion) {
KeychainDatabase.this.onDowngrade(); KeychainDatabase.this.onDowngrade();
} }
@@ -86,12 +90,19 @@ public class KeychainDatabase {
if (!db.isReadOnly()) { if (!db.isReadOnly()) {
// Enable foreign key constraints // Enable foreign key constraints
db.execSQL("PRAGMA foreign_keys=ON;"); db.execSQL("PRAGMA foreign_keys=ON;");
if (Constants.DEBUG) {
recreateUnifiedKeyView(db);
}
} }
} }
}).build()); }).build());
AndroidSqliteDriver driver = new AndroidSqliteDriver(supportSQLiteOpenHelper);
sqldelightDatabase = Database.Companion.invoke(driver,
new Autocrypt_peers.Adapter(CustomColumnAdapters.DATE_ADAPTER,
CustomColumnAdapters.DATE_ADAPTER,
CustomColumnAdapters.DATE_ADAPTER,
CustomColumnAdapters.GOSSIP_ORIGIN_ADAPTER),
new Certs.Adapter(CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER),
new Key_metadata.Adapter(CustomColumnAdapters.DATE_ADAPTER),
new Keys.Adapter(CustomColumnAdapters.SECRET_KEY_TYPE_ADAPTER)
);
} }
public SupportSQLiteDatabase getReadableDatabase() { public SupportSQLiteDatabase getReadableDatabase() {
@@ -102,328 +113,85 @@ public class KeychainDatabase {
return supportSQLiteOpenHelper.getWritableDatabase(); return supportSQLiteOpenHelper.getWritableDatabase();
} }
public Database getSqlDelightDatabase() {
return sqldelightDatabase;
}
@SuppressWarnings("deprecation") // using some sqldelight constants @SuppressWarnings("deprecation") // using some sqldelight constants
private void onCreate(SupportSQLiteDatabase db, Context context) { private void onCreate(SupportSQLiteDatabase db, Context context) {
Timber.w("Creating database..."); Timber.w("Creating database...");
db.execSQL(KeyRingsPublicModel.CREATE_TABLE); AndroidSqliteDriver sqlDriver = new AndroidSqliteDriver(db);
db.execSQL(KeysModel.CREATE_TABLE); Database.Companion.getSchema().create(sqlDriver);
db.execSQL(UserPacketsModel.CREATE_TABLE); recreateDatabaseViews(db);
db.execSQL(CertsModel.CREATE_TABLE);
db.execSQL(KeyMetadataModel.CREATE_TABLE);
db.execSQL(KeySignaturesModel.CREATE_TABLE);
db.execSQL(ApiAppsModel.CREATE_TABLE);
db.execSQL(OverriddenWarningsModel.CREATE_TABLE);
db.execSQL(AutocryptPeersModel.CREATE_TABLE);
db.execSQL(ApiAllowedKeysModel.CREATE_TABLE);
db.execSQL(KeysModel.UNIFIEDKEYVIEW);
db.execSQL(KeysModel.VALIDKEYSVIEW);
db.execSQL(KeysModel.VALIDMASTERKEYSVIEW);
db.execSQL(UserPacketsModel.UIDSTATUS);
db.execSQL("CREATE INDEX keys_by_rank ON keys (" + KeysModel.RANK + ", " + KeysModel.MASTER_KEY_ID + ");"); db.execSQL("CREATE INDEX keys_by_rank ON keys (rank, master_key_id);");
db.execSQL("CREATE INDEX uids_by_rank ON user_packets (" + UserPacketsModel.RANK + ", " db.execSQL("CREATE INDEX uids_by_rank ON user_packets (rank, user_id, master_key_id);");
+ UserPacketsModel.USER_ID + ", " + UserPacketsModel.MASTER_KEY_ID + ");"); db.execSQL("CREATE INDEX verified_certs ON certs (verified, master_key_id);");
db.execSQL("CREATE INDEX verified_certs ON certs (" db.execSQL("CREATE INDEX uids_by_email ON user_packets (email);");
+ CertsModel.VERIFIED + ", " + CertsModel.MASTER_KEY_ID + ");");
db.execSQL("CREATE INDEX uids_by_email ON user_packets ("
+ UserPacketsModel.EMAIL + ");");
Preferences.getPreferences(context).setKeySignaturesTableInitialized(); Preferences.getPreferences(context).setKeySignaturesTableInitialized();
} }
private void onUpgrade(SupportSQLiteDatabase db, Context context, int oldVersion, int newVersion) { private void onUpgrade(SupportSQLiteDatabase db, Context context, int oldVersion,
int newVersion) {
Timber.d("Upgrading db from " + oldVersion + " to " + newVersion); Timber.d("Upgrading db from " + oldVersion + " to " + newVersion);
if (oldVersion < 34) {
throw new IllegalStateException("upgrades from older versions not supported");
}
switch (oldVersion) { switch (oldVersion) {
case 1: case 34:
// add has_secret for all who are upgrading from a beta version // nothing
try {
db.execSQL("ALTER TABLE keys ADD COLUMN has_secret INTEGER");
} catch (Exception e) {
// never mind, the column probably already existed
}
// fall through
case 2:
// ECC support
try {
db.execSQL("ALTER TABLE keys ADD COLUMN key_curve_oid TEXT");
} catch (Exception e) {
// never mind, the column probably already existed
}
// fall through
case 3:
// better s2k detection, we need consolidate
// fall through
case 4:
try {
db.execSQL("ALTER TABLE keys ADD COLUMN can_authenticate INTEGER");
} catch (Exception e) {
// never mind, the column probably already existed
}
// fall through
case 5:
// do consolidate for 3.0 beta3
// fall through
case 6:
db.execSQL("ALTER TABLE user_ids ADD COLUMN type INTEGER");
db.execSQL("ALTER TABLE user_ids ADD COLUMN attribute_data BLOB");
case 7:
// new table for allowed key ids in API
try {
db.execSQL(ApiAppsModel.CREATE_TABLE);
} catch (Exception e) {
// never mind, the column probably already existed
}
case 8:
// tbale name for user_ids changed to user_packets
db.execSQL("DROP TABLE IF EXISTS certs");
db.execSQL("DROP TABLE IF EXISTS user_ids");
db.execSQL("CREATE TABLE IF NOT EXISTS user_packets("
+ "master_key_id INTEGER, "
+ "type INT, "
+ "user_id TEXT, "
+ "attribute_data BLOB, "
+ "is_primary INTEGER, "
+ "is_revoked INTEGER, "
+ "rank INTEGER, "
+ "PRIMARY KEY(master_key_id, rank), "
+ "FOREIGN KEY(master_key_id) REFERENCES "
+ "keyrings_public(master_key_id) ON DELETE CASCADE"
+ ")");
db.execSQL("CREATE TABLE IF NOT EXISTS certs("
+ "master_key_id INTEGER,"
+ "rank INTEGER, " // rank of certified uid
+ "key_id_certifier INTEGER, " // certifying key
+ "type INTEGER, "
+ "verified INTEGER, "
+ "creation INTEGER, "
+ "data BLOB, "
+ "PRIMARY KEY(master_key_id, rank, "
+ "key_id_certifier), "
+ "FOREIGN KEY(master_key_id) REFERENCES "
+ "keyrings_public(master_key_id) ON DELETE CASCADE,"
+ "FOREIGN KEY(master_key_id, rank) REFERENCES "
+ "user_packets(master_key_id, rank) ON DELETE CASCADE"
+ ")");
case 9:
// do nothing here, just consolidate
case 10:
// fix problems in database, see #1402 for details
// https://github.com/open-keychain/open-keychain/issues/1402
// no longer needed, api_accounts is deprecated
// db.execSQL("DELETE FROM api_accounts WHERE key_id BETWEEN 0 AND 3");
case 11:
db.execSQL("CREATE TABLE IF NOT EXISTS updated_keys ("
+ "master_key_id INTEGER PRIMARY KEY, "
+ "last_updated INTEGER, "
+ "FOREIGN KEY(master_key_id) REFERENCES "
+ "keyrings_public(master_key_id) ON DELETE CASCADE"
+ ")");
case 12:
// do nothing here, just consolidate
case 13:
db.execSQL("CREATE INDEX keys_by_rank ON keys (rank);");
db.execSQL("CREATE INDEX uids_by_rank ON user_packets (rank, user_id, master_key_id);");
db.execSQL("CREATE INDEX verified_certs ON certs (verified, master_key_id);");
case 14:
db.execSQL("ALTER TABLE user_packets ADD COLUMN name TEXT");
db.execSQL("ALTER TABLE user_packets ADD COLUMN email TEXT");
db.execSQL("ALTER TABLE user_packets ADD COLUMN comment TEXT");
case 15:
db.execSQL("CREATE INDEX uids_by_name ON user_packets (name COLLATE NOCASE)");
db.execSQL("CREATE INDEX uids_by_email ON user_packets (email COLLATE NOCASE)");
case 16:
// splitUserId changed: Execute consolidate for new parsing of name, email
case 17:
// splitUserId changed: Execute consolidate for new parsing of name, email
case 18:
db.execSQL("ALTER TABLE keys ADD COLUMN is_secure INTEGER");
case 19:
// emergency fix for crashing consolidate
db.execSQL("UPDATE keys SET is_secure = 1;");
case 20:
db.execSQL(
"CREATE TABLE IF NOT EXISTS overridden_warnings ("
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "identifier TEXT NOT NULL UNIQUE "
+ ")");
case 21:
try {
db.execSQL("ALTER TABLE updated_keys ADD COLUMN seen_on_keyservers INTEGER;");
} catch (SQLiteException e) {
// don't bother, the column probably already existed
}
case 22:
db.execSQL("CREATE TABLE IF NOT EXISTS api_autocrypt_peers ("
+ "package_name TEXT NOT NULL, "
+ "identifier TEXT NOT NULL, "
+ "last_updated INTEGER NOT NULL, "
+ "last_seen_key INTEGER NOT NULL, "
+ "state INTEGER NOT NULL, "
+ "master_key_id INTEGER, "
+ "PRIMARY KEY(package_name, identifier), "
+ "FOREIGN KEY(package_name) REFERENCES api_apps(package_name) ON DELETE CASCADE"
+ ")");
case 23:
db.execSQL("CREATE TABLE IF NOT EXISTS key_signatures ("
+ "master_key_id INTEGER NOT NULL, "
+ "signer_key_id INTEGER NOT NULL, "
+ "PRIMARY KEY(master_key_id, signer_key_id), "
+ "FOREIGN KEY(master_key_id) REFERENCES keyrings_public(master_key_id) ON DELETE CASCADE"
+ ")");
case 24: {
db.execSQL("ALTER TABLE api_autocrypt_peers RENAME TO tmp");
db.execSQL("CREATE TABLE api_autocrypt_peers ("
+ "package_name TEXT NOT NULL, "
+ "identifier TEXT NOT NULL, "
+ "last_seen INTEGER, "
+ "last_seen_key INTEGER, "
+ "is_mutual INTEGER, "
+ "master_key_id INTEGER, "
+ "gossip_master_key_id INTEGER, "
+ "gossip_last_seen_key INTEGER, "
+ "gossip_origin INTEGER, "
+ "PRIMARY KEY(package_name, identifier), "
+ "FOREIGN KEY(package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE"
+ ")");
// Note: Keys from Autocrypt 0.X with state == "reset" (0) are dropped
db.execSQL("INSERT INTO api_autocrypt_peers " +
"(package_name, identifier, last_seen, gossip_last_seen_key, gossip_master_key_id, gossip_origin) " +
"SELECT package_name, identifier, last_updated, last_seen_key, master_key_id, 0 " +
"FROM tmp WHERE state = 1"); // Autocrypt 0.X, "gossip" -> now origin=autocrypt
db.execSQL("INSERT INTO api_autocrypt_peers " +
"(package_name, identifier, last_seen, gossip_last_seen_key, gossip_master_key_id, gossip_origin) " +
"SELECT package_name, identifier, last_updated, last_seen_key, master_key_id, 20 " +
"FROM tmp WHERE state = 2"); // "selected" keys -> now origin=dedup
db.execSQL("INSERT INTO api_autocrypt_peers " +
"(package_name, identifier, last_seen, last_seen_key, master_key_id, is_mutual) " +
"SELECT package_name, identifier, last_updated, last_seen_key, master_key_id, 0 " +
"FROM tmp WHERE state = 3"); // Autocrypt 0.X, state = "available"
db.execSQL("INSERT INTO api_autocrypt_peers " +
"(package_name, identifier, last_seen, last_seen_key, master_key_id, is_mutual) " +
"SELECT package_name, identifier, last_updated, last_seen_key, master_key_id, 1 " +
"FROM tmp WHERE state = 4"); // from Autocrypt 0.X, state = "mutual"
db.execSQL("DROP TABLE tmp");
db.execSQL("CREATE INDEX IF NOT EXISTS uids_by_email ON user_packets (email);");
db.execSQL("DROP INDEX keys_by_rank");
db.execSQL("CREATE INDEX keys_by_rank ON keys(rank, master_key_id);");
}
case 25: {
try {
migrateSecretKeysFromDbToLocalStorage(db, context);
} catch (IOException e) {
throw new IllegalStateException("Error migrating secret keys! This is bad!!");
}
}
case 26:
migrateUpdatedKeysToKeyMetadataTable(db);
case 27:
renameApiAutocryptPeersTable(db);
case 28:
// drop old table from version 20
db.execSQL("DROP TABLE IF EXISTS api_accounts");
case 29:
recreateUnifiedKeyView(db);
case 30:
// ignore. this case only came up in an unreleased beta.
case 31:
addSubkeyValidFromField(db);
case 32:
recreateUnifiedKeyView(db);
case 33:
dropKeyMetadataForeignKey(db);
} }
// recreate the unified key view on any upgrade
recreateDatabaseViews(db);
} }
private void addSubkeyValidFromField(SupportSQLiteDatabase db) { private static void recreateDatabaseViews(SupportSQLiteDatabase db) {
try { // for some reason those aren't created as part of the schema. so we do it here.
db.execSQL("ALTER TABLE keys ADD COLUMN validFrom INTEGER NOT NULL DEFAULT 0;"); db.execSQL("DROP VIEW IF EXISTS unifiedKeyView");
db.execSQL("UPDATE keys SET validFrom = creation"); db.execSQL(
} catch (SQLiteException e) { """
// column probably already existed, nvm this CREATE VIEW unifiedKeyView AS
} SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.user_id, user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, keys.can_certify, certs.verified,
} (EXISTS (SELECT * FROM user_packets AS dups WHERE dups.master_key_id != keys.master_key_id AND dups.rank = 0 AND dups.name = user_packets.name COLLATE NOCASE AND dups.email = user_packets.email COLLATE NOCASE )) AS has_duplicate,
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.has_secret != 0)) AS has_any_secret,
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_encrypt != 0)) AS has_encrypt_key,
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_sign != 0)) AS has_sign_key,
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_authenticate != 0)) AS has_auth_key,
GROUP_CONCAT(DISTINCT aTI.package_name) AS autocrypt_package_names_csv,
GROUP_CONCAT(user_packets.user_id, '|||') AS user_id_list
FROM keys
INNER JOIN user_packets ON ( keys.master_key_id = user_packets.master_key_id AND user_packets.type IS NULL AND (user_packets.rank = 0 OR user_packets.is_revoked = 0))
LEFT JOIN certs ON ( keys.master_key_id = certs.master_key_id AND certs.verified = 1 )
LEFT JOIN autocrypt_peers AS aTI ON ( aTI.master_key_id = keys.master_key_id )
WHERE keys.rank = 0
GROUP BY keys.master_key_id;""");
db.execSQL("DROP VIEW IF EXISTS validKeys");
db.execSQL("""
CREATE VIEW validKeys AS
SELECT master_key_id, rank, key_id, key_size, key_curve_oid, algorithm, fingerprint, can_certify, can_sign, can_encrypt, can_authenticate, is_revoked, has_secret, is_secure, creation, expiry
FROM keys
WHERE is_revoked = 0 AND is_secure = 1 AND (expiry IS NULL OR expiry >= strftime('%s', 'now')) AND validFrom <= strftime('%s', 'now');
""");
db.execSQL("DROP VIEW IF EXISTS uidStatus");
db.execSQL("""
CREATE VIEW uidStatus AS
SELECT user_packets.email, MIN(certs.verified) AS key_status_int, user_packets.user_id, user_packets.master_key_id, COUNT(DISTINCT user_packets.master_key_id) AS candidates
FROM user_packets
JOIN validMasterKeys USING (master_key_id)
LEFT JOIN certs ON (certs.master_key_id = user_packets.master_key_id AND certs.rank = user_packets.rank AND certs.verified > 0)
WHERE user_packets.email IS NOT NULL
GROUP BY user_packets.email;
""");
db.execSQL("DROP VIEW IF EXISTS validMasterKeys");
db.execSQL("""
CREATE VIEW validMasterKeys AS
SELECT *
FROM validKeys
WHERE rank = 0;
""");
private void recreateUnifiedKeyView(SupportSQLiteDatabase db) {
// noinspection deprecation
db.execSQL("DROP VIEW IF EXISTS " + KeysModel.UNIFIEDKEYVIEW_VIEW_NAME);
db.execSQL(KeysModel.UNIFIEDKEYVIEW);
// noinspection deprecation
db.execSQL("DROP VIEW IF EXISTS " + KeysModel.VALIDKEYS_VIEW_NAME);
db.execSQL(KeysModel.VALIDKEYSVIEW);
// noinspection deprecation
db.execSQL("DROP VIEW IF EXISTS " + KeysModel.VALIDMASTERKEYS_VIEW_NAME);
db.execSQL(KeysModel.VALIDMASTERKEYSVIEW);
// noinspection deprecation
db.execSQL("DROP VIEW IF EXISTS " + UserPacketsModel.UIDSTATUS_VIEW_NAME);
db.execSQL(UserPacketsModel.UIDSTATUS);
}
private void dropKeyMetadataForeignKey(SupportSQLiteDatabase db) {
// noinspection deprecation
db.execSQL("ALTER TABLE " + KeyMetadataModel.TABLE_NAME + " RENAME TO metadata_tmp");
db.execSQL(KeyMetadataModel.CREATE_TABLE);
// noinspection deprecation
db.execSQL("INSERT INTO " + KeyMetadataModel.TABLE_NAME + " SELECT * FROM metadata_tmp");
db.execSQL("DROP TABLE metadata_tmp");
}
private void migrateSecretKeysFromDbToLocalStorage(SupportSQLiteDatabase db, Context context) throws IOException {
LocalSecretKeyStorage localSecretKeyStorage = LocalSecretKeyStorage.getInstance(context);
Cursor cursor = db.query("SELECT master_key_id, key_ring_data FROM keyrings_secret");
while (cursor.moveToNext()) {
long masterKeyId = cursor.getLong(0);
byte[] secretKeyBlob = cursor.getBlob(1);
localSecretKeyStorage.writeSecretKey(masterKeyId, secretKeyBlob);
}
cursor.close();
// we'll keep this around for now, but make sure to delete when migration looks ok!!
// db.execSQL("DROP TABLE keyrings_secret");
}
private void migrateUpdatedKeysToKeyMetadataTable(SupportSQLiteDatabase db) {
try {
db.execSQL("ALTER TABLE updated_keys RENAME TO key_metadata;");
} catch (SQLException e) {
if (Constants.DEBUG) {
Timber.e(e, "Ignoring migration exception, this probably happened before");
return;
}
throw e;
}
}
private void renameApiAutocryptPeersTable(SupportSQLiteDatabase db) {
try {
db.execSQL("ALTER TABLE api_autocrypt_peers RENAME TO autocrypt_peers;");
} catch (SQLException e) {
if (Constants.DEBUG) {
Timber.e(e, "Ignoring migration exception, this probably happened before");
return;
}
throw e;
}
} }
private void onDowngrade() { private void onDowngrade() {
@@ -468,7 +236,7 @@ public class KeychainDatabase {
out.createNewFile(); out.createNewFile();
} }
if (!in.canRead()) { if (!in.canRead()) {
throw new IOException("Cannot read " + in.getName()); throw new IOException("Cannot read " + in.getName());
} }
if (!out.canWrite()) { if (!out.canWrite()) {
throw new IOException("Cannot write " + out.getName()); throw new IOException("Cannot write " + out.getName());

View File

@@ -1,16 +1,9 @@
package org.sufficientlysecure.keychain.daos; package org.sufficientlysecure.keychain.daos;
import java.util.ArrayList;
import java.util.List;
import androidx.sqlite.db.SupportSQLiteDatabase; import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.sqlite.db.SupportSQLiteQuery; import org.sufficientlysecure.keychain.Database;
import android.database.Cursor;
import com.squareup.sqldelight.RowMapper;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
class AbstractDao { class AbstractDao {
@@ -22,8 +15,8 @@ class AbstractDao {
this.databaseNotifyManager = databaseNotifyManager; this.databaseNotifyManager = databaseNotifyManager;
} }
SupportSQLiteDatabase getReadableDb() { Database getDatabase() {
return db.getReadableDatabase(); return db.getSqlDelightDatabase();
} }
SupportSQLiteDatabase getWritableDb() { SupportSQLiteDatabase getWritableDb() {
@@ -33,32 +26,4 @@ class AbstractDao {
DatabaseNotifyManager getDatabaseNotifyManager() { DatabaseNotifyManager getDatabaseNotifyManager() {
return databaseNotifyManager; return databaseNotifyManager;
} }
<T> List<T> mapAllRows(SupportSQLiteQuery query, RowMapper<T> mapper) {
ArrayList<T> result = new ArrayList<>();
try (Cursor cursor = getReadableDb().query(query)) {
while (cursor.moveToNext()) {
T item = mapper.map(cursor);
result.add(item);
}
}
return result;
}
<T> T mapSingleRowOrThrow(SupportSQLiteQuery query, RowMapper<T> mapper) throws NotFoundException {
T result = mapSingleRow(query, mapper);
if (result == null) {
throw new NotFoundException();
}
return result;
}
<T> T mapSingleRow(SupportSQLiteQuery query, RowMapper<T> mapper) {
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToNext()) {
return mapper.map(cursor);
}
}
return null;
}
} }

View File

@@ -18,26 +18,25 @@
package org.sufficientlysecure.keychain.daos; package org.sufficientlysecure.keychain.daos;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import android.content.Context; import android.content.Context;
import android.database.Cursor;
import com.squareup.sqldelight.SqlDelightQuery; import org.sufficientlysecure.keychain.ApiAllowedKeysQueries;
import org.sufficientlysecure.keychain.ApiAllowedKeysModel.InsertAllowedKey; import org.sufficientlysecure.keychain.ApiAppsQueries;
import org.sufficientlysecure.keychain.ApiAppsModel; import org.sufficientlysecure.keychain.Api_apps;
import org.sufficientlysecure.keychain.ApiAppsModel.DeleteByPackageName; import org.sufficientlysecure.keychain.GetCertificate;
import org.sufficientlysecure.keychain.ApiAppsModel.InsertApiApp;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.model.ApiAllowedKey;
import org.sufficientlysecure.keychain.model.ApiApp;
public class ApiAppDao extends AbstractDao { public class ApiAppDao extends AbstractDao {
private final ApiAppsQueries apiAppsQueries = getDatabase().getApiAppsQueries();
private final ApiAllowedKeysQueries apiAllowedKeysQueries =
getDatabase().getApiAllowedKeysQueries();
public static ApiAppDao getInstance(Context context) { public static ApiAppDao getInstance(Context context) {
KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context); KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context);
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context); DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
@@ -45,95 +44,75 @@ public class ApiAppDao extends AbstractDao {
return new ApiAppDao(keychainDatabase, databaseNotifyManager); return new ApiAppDao(keychainDatabase, databaseNotifyManager);
} }
private ApiAppDao(KeychainDatabase keychainDatabase, DatabaseNotifyManager databaseNotifyManager) { private ApiAppDao(KeychainDatabase keychainDatabase,
DatabaseNotifyManager databaseNotifyManager) {
super(keychainDatabase, databaseNotifyManager); super(keychainDatabase, databaseNotifyManager);
} }
public ApiApp getApiApp(String packageName) { public Api_apps getApiApp(String packageName) {
try (Cursor cursor = getReadableDb().query(ApiApp.FACTORY.selectByPackageName(packageName))) { return apiAppsQueries.selectByPackageName(packageName).executeAsOneOrNull();
if (cursor.moveToFirst()) {
return ApiApp.FACTORY.selectByPackageNameMapper().map(cursor);
}
return null;
}
} }
public byte[] getApiAppCertificate(String packageName) { public byte[] getApiAppCertificate(String packageName) {
try (Cursor cursor = getReadableDb().query(ApiApp.FACTORY.getCertificate(packageName))) { GetCertificate getCertificate =
if (cursor.moveToFirst()) { apiAppsQueries.getCertificate(packageName).executeAsOneOrNull();
return ApiApp.FACTORY.getCertificateMapper().map(cursor); if (getCertificate == null) {
}
return null; return null;
} }
return getCertificate.getPackage_signature();
} }
public void insertApiApp(ApiApp apiApp) { public void insertApiApp(String packageName, byte[] signature) {
ApiApp existingApiApp = getApiApp(apiApp.package_name()); Api_apps existingApiApp = getApiApp(packageName);
if (existingApiApp != null) { if (existingApiApp != null) {
if (!Arrays.equals(existingApiApp.package_signature(), apiApp.package_signature())) { if (!Arrays.equals(existingApiApp.getPackage_signature(),
throw new IllegalStateException("Inserting existing api with different signature?!"); signature)) {
throw new IllegalStateException(
"Inserting existing api with different signature?!");
} }
return; return;
} }
InsertApiApp statement = new ApiAppsModel.InsertApiApp(getWritableDb()); apiAppsQueries.insertApiApp(packageName, signature);
statement.bind(apiApp.package_name(), apiApp.package_signature()); getDatabaseNotifyManager().notifyApiAppChange(packageName);
statement.executeInsert(); }
getDatabaseNotifyManager().notifyApiAppChange(apiApp.package_name()); public void insertApiApp(Api_apps apiApp) {
Api_apps existingApiApp = getApiApp(apiApp.getPackage_name());
if (existingApiApp != null) {
if (!Arrays.equals(existingApiApp.getPackage_signature(),
apiApp.getPackage_signature())) {
throw new IllegalStateException(
"Inserting existing api with different signature?!");
}
return;
}
apiAppsQueries.insertApiApp(apiApp.getPackage_name(), apiApp.getPackage_signature());
getDatabaseNotifyManager().notifyApiAppChange(apiApp.getPackage_name());
} }
public void deleteApiApp(String packageName) { public void deleteApiApp(String packageName) {
DeleteByPackageName deleteByPackageName = new DeleteByPackageName(getWritableDb()); apiAppsQueries.deleteByPackageName(packageName);
deleteByPackageName.bind(packageName);
deleteByPackageName.executeUpdateDelete();
getDatabaseNotifyManager().notifyApiAppChange(packageName); getDatabaseNotifyManager().notifyApiAppChange(packageName);
} }
public HashSet<Long> getAllowedKeyIdsForApp(String packageName) { public HashSet<Long> getAllowedKeyIdsForApp(String packageName) {
SqlDelightQuery allowedKeys = ApiAllowedKey.FACTORY.getAllowedKeys(packageName); return new HashSet<>(apiAllowedKeysQueries.getAllowedKeys(packageName).executeAsList());
HashSet<Long> keyIds = new HashSet<>();
try (Cursor cursor = getReadableDb().query(allowedKeys)) {
while (cursor.moveToNext()) {
long allowedKeyId = ApiAllowedKey.FACTORY.getAllowedKeysMapper().map(cursor);
keyIds.add(allowedKeyId);
}
}
return keyIds;
} }
public void saveAllowedKeyIdsForApp(String packageName, Set<Long> allowedKeyIds) { public void saveAllowedKeyIdsForApp(String packageName, Set<Long> allowedKeyIds) {
ApiAllowedKey.DeleteByPackageName deleteByPackageName = new ApiAllowedKey.DeleteByPackageName(getWritableDb()); apiAllowedKeysQueries.deleteByPackageName(packageName);
deleteByPackageName.bind(packageName);
deleteByPackageName.executeUpdateDelete();
InsertAllowedKey statement = new InsertAllowedKey(getWritableDb());
for (Long keyId : allowedKeyIds) { for (Long keyId : allowedKeyIds) {
statement.bind(packageName, keyId); apiAllowedKeysQueries.insertAllowedKey(packageName, keyId);
statement.execute();
} }
getDatabaseNotifyManager().notifyApiAppChange(packageName); getDatabaseNotifyManager().notifyApiAppChange(packageName);
} }
public void addAllowedKeyIdForApp(String packageName, long allowedKeyId) { public void addAllowedKeyIdForApp(String packageName, long allowedKeyId) {
InsertAllowedKey statement = new InsertAllowedKey(getWritableDb()); apiAllowedKeysQueries.insertAllowedKey(packageName, allowedKeyId);
statement.bind(packageName, allowedKeyId);
statement.executeInsert();
getDatabaseNotifyManager().notifyApiAppChange(packageName); getDatabaseNotifyManager().notifyApiAppChange(packageName);
} }
public List<ApiApp> getAllApiApps() { public List<Api_apps> getAllApiApps() {
SqlDelightQuery query = ApiApp.FACTORY.selectAll(); return apiAppsQueries.selectAll().executeAsList();
ArrayList<ApiApp> result = new ArrayList<>();
try (Cursor cursor = getReadableDb().query(query)) {
while (cursor.moveToNext()) {
ApiApp apiApp = ApiApp.FACTORY.selectAllMapper().map(cursor);
result.add(apiApp);
}
}
return result;
} }
} }

View File

@@ -18,28 +18,26 @@
package org.sufficientlysecure.keychain.daos; package org.sufficientlysecure.keychain.daos;
import java.util.ArrayList; import java.util.Arrays;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import android.content.Context; import android.content.Context;
import android.database.Cursor;
import androidx.annotation.Nullable;
import com.squareup.sqldelight.SqlDelightQuery; import androidx.annotation.Nullable;
import org.sufficientlysecure.keychain.AutocryptPeersModel.DeleteByIdentifier; import org.sufficientlysecure.keychain.AutocryptPeersQueries;
import org.sufficientlysecure.keychain.AutocryptPeersModel.DeleteByMasterKeyId; import org.sufficientlysecure.keychain.Autocrypt_peers;
import org.sufficientlysecure.keychain.AutocryptPeersModel.InsertPeer;
import org.sufficientlysecure.keychain.AutocryptPeersModel.UpdateGossipKey;
import org.sufficientlysecure.keychain.AutocryptPeersModel.UpdateKey;
import org.sufficientlysecure.keychain.AutocryptPeersModel.UpdateLastSeen;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.model.AutocryptPeer; import org.sufficientlysecure.keychain.SelectAutocryptKeyStatus;
import org.sufficientlysecure.keychain.model.AutocryptPeer.AutocryptKeyStatus; import org.sufficientlysecure.keychain.SelectMasterKeyIdByIdentifier;
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin; import org.sufficientlysecure.keychain.model.GossipOrigin;
public class AutocryptPeerDao extends AbstractDao { public class AutocryptPeerDao extends AbstractDao {
private final AutocryptPeersQueries autocryptPeersQueries =
getDatabase().getAutocryptPeersQueries();
public static AutocryptPeerDao getInstance(Context context) { public static AutocryptPeerDao getInstance(Context context) {
KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context); KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context);
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context); DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
@@ -47,100 +45,78 @@ public class AutocryptPeerDao extends AbstractDao {
return new AutocryptPeerDao(keychainDatabase, databaseNotifyManager); return new AutocryptPeerDao(keychainDatabase, databaseNotifyManager);
} }
private AutocryptPeerDao(KeychainDatabase database, DatabaseNotifyManager databaseNotifyManager) { private AutocryptPeerDao(KeychainDatabase database,
DatabaseNotifyManager databaseNotifyManager) {
super(database, databaseNotifyManager); super(database, databaseNotifyManager);
} }
public Long getMasterKeyIdForAutocryptPeer(String autocryptId) { public Long getMasterKeyIdForAutocryptPeer(String autocryptId) {
SqlDelightQuery query = AutocryptPeer.FACTORY.selectMasterKeyIdByIdentifier(autocryptId); SelectMasterKeyIdByIdentifier masterKeyId =
try (Cursor cursor = getReadableDb().query(query)) { autocryptPeersQueries.selectMasterKeyIdByIdentifier(autocryptId)
if (cursor.moveToFirst()) { .executeAsOneOrNull();
return AutocryptPeer.FACTORY.selectMasterKeyIdByIdentifierMapper().map(cursor); if (masterKeyId != null) {
} return masterKeyId.getMaster_key_id();
} }
return null; return null;
} }
@Nullable @Nullable
public AutocryptPeer getAutocryptPeer(String packageName, String autocryptId) { public Autocrypt_peers getAutocryptPeer(String packageName, String autocryptId) {
List<AutocryptPeer> autocryptPeers = getAutocryptPeers(packageName, autocryptId); return autocryptPeersQueries.selectByIdentifiers(packageName,
if (!autocryptPeers.isEmpty()) { Collections.singleton(autocryptId)).executeAsOneOrNull();
return autocryptPeers.get(0);
}
return null;
} }
private List<AutocryptPeer> getAutocryptPeers(String packageName, String... autocryptId) { private List<Autocrypt_peers> getAutocryptPeers(String packageName, String... autocryptId) {
SqlDelightQuery query = AutocryptPeer.FACTORY.selectByIdentifiers(packageName, autocryptId); return autocryptPeersQueries.selectByIdentifiers(packageName, Arrays.asList(autocryptId))
return mapAllRows(query, AutocryptPeer.PEER_MAPPER); .executeAsList();
} }
public List<AutocryptKeyStatus> getAutocryptKeyStatus(String packageName, String[] autocryptIds) { public List<SelectAutocryptKeyStatus> getAutocryptKeyStatus(String packageName,
SqlDelightQuery query = AutocryptPeer.FACTORY.selectAutocryptKeyStatus(packageName, autocryptIds); String[] autocryptIds) {
return mapAllRows(query, AutocryptPeer.KEY_STATUS_MAPPER); return autocryptPeersQueries.selectAutocryptKeyStatus(packageName,
Arrays.asList(autocryptIds)).executeAsList();
} }
private void ensureAutocryptPeerExists(String packageName, String autocryptId) { private void ensureAutocryptPeerExists(String packageName, String autocryptId) {
InsertPeer insertStatement = new InsertPeer(getWritableDb()); autocryptPeersQueries.insertPeer(packageName, autocryptId);
insertStatement.bind(packageName, autocryptId);
insertStatement.executeInsert();
} }
public void insertOrUpdateLastSeen(String packageName, String autocryptId, Date date) { public void insertOrUpdateLastSeen(String packageName, String autocryptId, Date date) {
ensureAutocryptPeerExists(packageName, autocryptId); ensureAutocryptPeerExists(packageName, autocryptId);
autocryptPeersQueries.updateLastSeen(packageName, autocryptId, date);
UpdateLastSeen updateStatement = new UpdateLastSeen(getWritableDb(), AutocryptPeer.FACTORY);
updateStatement.bind(packageName, autocryptId, date);
updateStatement.executeUpdateDelete();
} }
public void updateKey(String packageName, String autocryptId, Date effectiveDate, long masterKeyId, public void updateKey(String packageName, String autocryptId, Date effectiveDate,
long masterKeyId,
boolean isMutual) { boolean isMutual) {
ensureAutocryptPeerExists(packageName, autocryptId); ensureAutocryptPeerExists(packageName, autocryptId);
autocryptPeersQueries.updateKey(packageName, autocryptId, effectiveDate, masterKeyId,
UpdateKey updateStatement = new UpdateKey(getWritableDb(), AutocryptPeer.FACTORY); isMutual);
updateStatement.bind(packageName, autocryptId, effectiveDate, masterKeyId, isMutual);
updateStatement.executeUpdateDelete();
getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId); getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId);
} }
public void updateKeyGossip(String packageName, String autocryptId, Date effectiveDate, long masterKeyId, public void updateKeyGossip(String packageName, String autocryptId, Date effectiveDate,
long masterKeyId,
GossipOrigin origin) { GossipOrigin origin) {
ensureAutocryptPeerExists(packageName, autocryptId); ensureAutocryptPeerExists(packageName, autocryptId);
autocryptPeersQueries.updateGossipKey(packageName, autocryptId, effectiveDate, masterKeyId,
UpdateGossipKey updateStatement = new UpdateGossipKey(getWritableDb(), AutocryptPeer.FACTORY); origin);
updateStatement.bind(packageName, autocryptId, effectiveDate, masterKeyId, origin);
updateStatement.executeUpdateDelete();
getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId); getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId);
} }
public List<AutocryptPeer> getAutocryptPeersForKey(long masterKeyId) { public List<Autocrypt_peers> getAutocryptPeersForKey(long masterKeyId) {
ArrayList<AutocryptPeer> result = new ArrayList<>(); return autocryptPeersQueries.selectByMasterKeyId(masterKeyId).executeAsList();
SqlDelightQuery query = AutocryptPeer.FACTORY.selectByMasterKeyId(masterKeyId);
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToNext()) {
AutocryptPeer autocryptPeer = AutocryptPeer.PEER_MAPPER.map(cursor);
result.add(autocryptPeer);
}
}
return result;
} }
public void deleteByIdentifier(String packageName, String autocryptId) { public void deleteByIdentifier(String packageName, String autocryptId) {
Long masterKeyId = getMasterKeyIdForAutocryptPeer(autocryptId); Long masterKeyId = getMasterKeyIdForAutocryptPeer(autocryptId);
DeleteByIdentifier deleteStatement = new DeleteByIdentifier(getReadableDb()); autocryptPeersQueries.deleteByIdentifier(packageName, autocryptId);
deleteStatement.bind(packageName, autocryptId);
deleteStatement.execute();
if (masterKeyId != null) { if (masterKeyId != null) {
getDatabaseNotifyManager().notifyAutocryptDelete(autocryptId, masterKeyId); getDatabaseNotifyManager().notifyAutocryptDelete(autocryptId, masterKeyId);
} }
} }
public void deleteByMasterKeyId(long masterKeyId) { public void deleteByMasterKeyId(long masterKeyId) {
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(getReadableDb()); autocryptPeersQueries.deleteByMasterKeyId(masterKeyId);
deleteStatement.bind(masterKeyId);
deleteStatement.execute();
} }
} }

View File

@@ -2,12 +2,9 @@ package org.sufficientlysecure.keychain.daos;
import android.content.Context; import android.content.Context;
import android.database.Cursor;
import com.squareup.sqldelight.SqlDelightQuery;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.model.Certification; import org.sufficientlysecure.keychain.SelectVerifyingCertDetails;
import org.sufficientlysecure.keychain.model.Certification.CertDetails;
public class CertificationDao extends AbstractDao { public class CertificationDao extends AbstractDao {
@@ -22,14 +19,8 @@ public class CertificationDao extends AbstractDao {
super(keychainDatabase, databaseNotifyManager); super(keychainDatabase, databaseNotifyManager);
} }
public CertDetails getVerifyingCertDetails(long masterKeyId, int userPacketRank) { public SelectVerifyingCertDetails getVerifyingCertDetails(long masterKeyId, int userPacketRank) {
SqlDelightQuery query = Certification.FACTORY.selectVerifyingCertDetails(masterKeyId, userPacketRank); return getDatabase().getCertsQueries().selectVerifyingCertDetails(masterKeyId, userPacketRank).executeAsOneOrNull();
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToFirst()) {
return Certification.CERT_DETAILS_MAPPER.map(cursor);
}
}
return null;
} }
} }

View File

@@ -3,95 +3,76 @@ package org.sufficientlysecure.keychain.daos;
import java.util.List; import java.util.List;
import androidx.sqlite.db.SupportSQLiteDatabase; import com.squareup.sqldelight.TransactionWithoutReturn;
import kotlin.Unit;
import org.sufficientlysecure.keychain.CertsModel.InsertCert; import kotlin.jvm.functions.Function1;
import org.sufficientlysecure.keychain.KeyRingsPublicModel.InsertKeyRingPublic; import org.sufficientlysecure.keychain.Certs;
import org.sufficientlysecure.keychain.KeySignaturesModel.InsertKeySignature; import org.sufficientlysecure.keychain.Database;
import org.sufficientlysecure.keychain.KeysModel.InsertKey; import org.sufficientlysecure.keychain.Key_signatures;
import org.sufficientlysecure.keychain.UserPacketsModel.InsertUserPacket; import org.sufficientlysecure.keychain.Keyrings_public;
import org.sufficientlysecure.keychain.model.Certification; import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.model.KeyRingPublic; import org.sufficientlysecure.keychain.User_packets;
import org.sufficientlysecure.keychain.model.KeySignature;
import org.sufficientlysecure.keychain.model.SubKey;
import org.sufficientlysecure.keychain.model.UserPacket;
public class DatabaseBatchInteractor { public class DatabaseBatchInteractor {
private final SupportSQLiteDatabase db; private final Database db;
private final InsertKeyRingPublic insertKeyRingPublicStatement; DatabaseBatchInteractor(Database db) {
private final InsertKey insertSubKeyStatement;
private final InsertUserPacket insertUserPacketStatement;
private final InsertCert insertCertificationStatement;
private final InsertKeySignature insertKeySignerStatement;
DatabaseBatchInteractor(SupportSQLiteDatabase db) {
this.db = db; this.db = db;
insertKeyRingPublicStatement = KeyRingPublic.createInsertStatement(db);
insertSubKeyStatement = SubKey.createInsertStatement(db);
insertUserPacketStatement = UserPacket.createInsertStatement(db);
insertCertificationStatement = Certification.createInsertStatement(db);
insertKeySignerStatement = KeySignature.createInsertStatement(db);
}
public SupportSQLiteDatabase getDb() {
return db;
} }
public void applyBatch(List<BatchOp> operations) { public void applyBatch(List<BatchOp> operations) {
for (BatchOp op : operations) { db.transaction(true,
if (op.keyRingPublic != null) { (Function1<TransactionWithoutReturn, Unit>) transactionWithoutReturn -> {
op.keyRingPublic.bindTo(insertKeyRingPublicStatement); for (BatchOp op : operations) {
insertKeyRingPublicStatement.executeInsert(); if (op.keyRingPublic != null) {
} else if (op.subKey != null) { db.getKeyRingsPublicQueries().insertKeyRingPublic(op.keyRingPublic);
op.subKey.bindTo(insertSubKeyStatement); } else if (op.subKey != null) {
insertSubKeyStatement.executeInsert(); db.getKeysQueries().insertKey(op.subKey);
} else if (op.userPacket != null) { } else if (op.userPacket != null) {
op.userPacket.bindTo(insertUserPacketStatement); db.getUserPacketsQueries().insertUserPacket(op.userPacket);
insertUserPacketStatement.executeInsert(); } else if (op.certification != null) {
} else if (op.certification != null) { db.getCertsQueries().insertCert(op.certification);
op.certification.bindTo(insertCertificationStatement); } else if (op.keySignature != null) {
insertCertificationStatement.executeInsert(); db.getKeySignaturesQueries().insertKeySignature(op.keySignature);
} else if (op.keySignature != null) { } else {
op.keySignature.bindTo(insertKeySignerStatement); throw new IllegalStateException();
insertKeySignerStatement.executeInsert(); }
} else { }
throw new IllegalStateException(); return Unit.INSTANCE;
} });
}
} }
public static BatchOp createInsertKeyRingPublic(KeyRingPublic keyRingPublic) { public static BatchOp createInsertKeyRingPublic(Keyrings_public keyRingPublic) {
return new BatchOp(keyRingPublic, null, null, null, null); return new BatchOp(keyRingPublic, null, null, null, null);
} }
static BatchOp createInsertSubKey(SubKey subKey) { static BatchOp createInsertSubKey(Keys subKey) {
return new BatchOp(null, subKey, null, null, null); return new BatchOp(null, subKey, null, null, null);
} }
public static BatchOp createInsertUserPacket(UserPacket userPacket) { public static BatchOp createInsertUserPacket(User_packets userPacket) {
return new BatchOp(null, null, userPacket, null, null); return new BatchOp(null, null, userPacket, null, null);
} }
public static BatchOp createInsertCertification(Certification certification) { public static BatchOp createInsertCertification(Certs certification) {
return new BatchOp(null, null, null, certification, null); return new BatchOp(null, null, null, certification, null);
} }
static BatchOp createInsertSignerKey(KeySignature keySignature) { static BatchOp createInsertSignerKey(Key_signatures keySignature) {
return new BatchOp(null, null, null, null, keySignature); return new BatchOp(null, null, null, null, keySignature);
} }
static class BatchOp { static class BatchOp {
final KeyRingPublic keyRingPublic; final Keyrings_public keyRingPublic;
final SubKey subKey; final Keys subKey;
final UserPacket userPacket; final User_packets userPacket;
final Certification certification; final Certs certification;
final KeySignature keySignature; final Key_signatures keySignature;
BatchOp(KeyRingPublic keyRingPublic, SubKey subKey, UserPacket userPacket, BatchOp(Keyrings_public keyRingPublic, Keys subKey, User_packets userPacket,
Certification certification, KeySignature keySignature) { Certs certification, Key_signatures keySignature) {
this.subKey = subKey; this.subKey = subKey;
this.keyRingPublic = keyRingPublic; this.keyRingPublic = keyRingPublic;
this.userPacket = userPacket; this.userPacket = userPacket;

View File

@@ -1,21 +1,20 @@
package org.sufficientlysecure.keychain.daos; package org.sufficientlysecure.keychain.daos;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import android.content.Context; import android.content.Context;
import android.database.Cursor;
import com.squareup.sqldelight.SqlDelightQuery; import org.sufficientlysecure.keychain.KeyMetadataQueries;
import org.sufficientlysecure.keychain.KeyMetadataModel.ReplaceKeyMetadata; import org.sufficientlysecure.keychain.Key_metadata;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.model.KeyMetadata;
public class KeyMetadataDao extends AbstractDao { public class KeyMetadataDao extends AbstractDao {
KeyMetadataQueries queries = getDatabase().getKeyMetadataQueries();
public static KeyMetadataDao create(Context context) { public static KeyMetadataDao create(Context context) {
KeychainDatabase database = KeychainDatabase.getInstance(context); KeychainDatabase database = KeychainDatabase.getInstance(context);
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context); DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
@@ -27,38 +26,21 @@ public class KeyMetadataDao extends AbstractDao {
super(database, databaseNotifyManager); super(database, databaseNotifyManager);
} }
public KeyMetadata getKeyMetadata(long masterKeyId) { public Key_metadata getKeyMetadata(long masterKeyId) {
SqlDelightQuery query = KeyMetadata.FACTORY.selectByMasterKeyId(masterKeyId); return queries.selectByMasterKeyId(masterKeyId).executeAsOneOrNull();
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToFirst()) {
return KeyMetadata.FACTORY.selectByMasterKeyIdMapper().map(cursor);
}
}
return null;
} }
public void resetAllLastUpdatedTimes() { public void resetAllLastUpdatedTimes() {
new KeyMetadata.DeleteAllLastUpdatedTimes(getWritableDb()).execute(); queries.deleteAllLastUpdatedTimes();
} }
public void renewKeyLastUpdatedTime(long masterKeyId, boolean seenOnKeyservers) { public void renewKeyLastUpdatedTime(long masterKeyId, boolean seenOnKeyservers) {
ReplaceKeyMetadata replaceStatement = new ReplaceKeyMetadata(getWritableDb(), KeyMetadata.FACTORY); queries.replaceKeyMetadata(masterKeyId, new Date(), seenOnKeyservers);
replaceStatement.bind(masterKeyId, new Date(), seenOnKeyservers);
replaceStatement.executeInsert();
getDatabaseNotifyManager().notifyKeyMetadataChange(masterKeyId); getDatabaseNotifyManager().notifyKeyMetadataChange(masterKeyId);
} }
public List<byte[]> getFingerprintsForKeysOlderThan(long olderThan, TimeUnit timeUnit) { public List<byte[]> getFingerprintsForKeysOlderThan(long olderThan, TimeUnit timeUnit) {
SqlDelightQuery query = KeyMetadata.FACTORY.selectFingerprintsForKeysOlderThan(new Date(timeUnit.toMillis(olderThan))); return queries.selectFingerprintsForKeysOlderThan(new Date(timeUnit.toMillis(olderThan)))
.executeAsList();
List<byte[]> fingerprintList = new ArrayList<>();
try (Cursor cursor = getReadableDb().query(query)) {
while (cursor.moveToNext()) {
byte[] fingerprint = KeyMetadata.FACTORY.selectFingerprintsForKeysOlderThanMapper().map(cursor);
fingerprintList.add(fingerprint);
}
}
return fingerprintList;
} }
} }

View File

@@ -20,22 +20,23 @@ package org.sufficientlysecure.keychain.daos;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.List; import java.util.List;
import android.content.Context; import android.content.Context;
import android.database.Cursor;
import androidx.annotation.WorkerThread;
import com.squareup.sqldelight.SqlDelightQuery; import androidx.annotation.WorkerThread;
import com.squareup.sqldelight.Query;
import com.squareup.sqldelight.db.SqlCursor;
import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.sufficientlysecure.keychain.KeyRingsPublicQueries;
import org.sufficientlysecure.keychain.KeySignaturesQueries;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.model.Certification; import org.sufficientlysecure.keychain.Keyrings_public;
import org.sufficientlysecure.keychain.model.KeyRingPublic; import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.model.KeySignature; import org.sufficientlysecure.keychain.KeysQueries;
import org.sufficientlysecure.keychain.model.SubKey; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UserId;
import org.sufficientlysecure.keychain.model.UserPacket;
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
@@ -49,9 +50,12 @@ import timber.log.Timber;
public class KeyRepository extends AbstractDao { public class KeyRepository extends AbstractDao {
final LocalPublicKeyStorage mLocalPublicKeyStorage; final LocalPublicKeyStorage mLocalPublicKeyStorage;
final LocalSecretKeyStorage localSecretKeyStorage; final LocalSecretKeyStorage localSecretKeyStorage;
private final KeysQueries keysQueries = getDatabase().getKeysQueries();
OperationLog mLog; OperationLog mLog;
int mIndent; int mIndent;
private final KeyRingsPublicQueries keyRingsPublicQueries = getDatabase().getKeyRingsPublicQueries();
private final KeySignaturesQueries keySignaturesQueries = getDatabase().getKeySignaturesQueries();
public static KeyRepository create(Context context) { public static KeyRepository create(Context context) {
LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context); LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context);
@@ -59,14 +63,16 @@ public class KeyRepository extends AbstractDao {
KeychainDatabase database = KeychainDatabase.getInstance(context); KeychainDatabase database = KeychainDatabase.getInstance(context);
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context); DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
return new KeyRepository(database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage); return new KeyRepository(database, databaseNotifyManager, localPublicKeyStorage,
localSecretKeyStorage);
} }
private KeyRepository(KeychainDatabase database, private KeyRepository(KeychainDatabase database,
DatabaseNotifyManager databaseNotifyManager, DatabaseNotifyManager databaseNotifyManager,
LocalPublicKeyStorage localPublicKeyStorage, LocalPublicKeyStorage localPublicKeyStorage,
LocalSecretKeyStorage localSecretKeyStorage) { LocalSecretKeyStorage localSecretKeyStorage) {
this(database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage, new OperationLog(), 0); this(database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage,
new OperationLog(), 0);
} }
KeyRepository(KeychainDatabase database, KeyRepository(KeychainDatabase database,
@@ -101,7 +107,8 @@ public class KeyRepository extends AbstractDao {
mLog = new OperationLog(); mLog = new OperationLog();
} }
public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long masterKeyId) throws NotFoundException { public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long masterKeyId)
throws NotFoundException {
UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId); UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
if (unifiedKeyInfo == null) { if (unifiedKeyInfo == null) {
throw new NotFoundException(); throw new NotFoundException();
@@ -111,7 +118,8 @@ public class KeyRepository extends AbstractDao {
return new CanonicalizedPublicKeyRing(publicKeyData, unifiedKeyInfo.verified()); return new CanonicalizedPublicKeyRing(publicKeyData, unifiedKeyInfo.verified());
} }
public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(long masterKeyId) throws NotFoundException { public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(long masterKeyId)
throws NotFoundException {
UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId); UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
if (unifiedKeyInfo == null || !unifiedKeyInfo.has_any_secret()) { if (unifiedKeyInfo == null || !unifiedKeyInfo.has_any_secret()) {
throw new NotFoundException(); throw new NotFoundException();
@@ -124,75 +132,85 @@ public class KeyRepository extends AbstractDao {
} }
public List<Long> getAllMasterKeyIds() { public List<Long> getAllMasterKeyIds() {
SqlDelightQuery query = KeyRingPublic.FACTORY.selectAllMasterKeyIds(); return keyRingsPublicQueries.selectAllMasterKeyIds().executeAsList();
return mapAllRows(query, KeySignature.FACTORY.selectMasterKeyIdsBySignerMapper());
} }
public List<Long> getMasterKeyIdsBySigner(List<Long> signerMasterKeyIds) { public List<Long> getMasterKeyIdsBySigner(List<Long> signerMasterKeyIds) {
long[] signerKeyIds = getLongListAsArray(signerMasterKeyIds); return keySignaturesQueries.selectMasterKeyIdsBySigner(signerMasterKeyIds).executeAsList();
SqlDelightQuery query = KeySignature.FACTORY.selectMasterKeyIdsBySigner(signerKeyIds);
return mapAllRows(query, KeySignature.FACTORY.selectMasterKeyIdsBySignerMapper());
} }
public Long getMasterKeyIdBySubkeyId(long subKeyId) { public Long getMasterKeyIdBySubkeyId(long subKeyId) {
SqlDelightQuery query = SubKey.FACTORY.selectMasterKeyIdBySubkey(subKeyId); return keysQueries.selectMasterKeyIdBySubkey(subKeyId).executeAsOneOrNull();
return mapSingleRow(query, SubKey.FACTORY.selectMasterKeyIdBySubkeyMapper());
} }
public UnifiedKeyInfo getUnifiedKeyInfo(long masterKeyId) { public UnifiedKeyInfo getUnifiedKeyInfo(long masterKeyId) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyId(masterKeyId); return keysQueries.selectUnifiedKeyInfoByMasterKeyId(masterKeyId, UnifiedKeyInfo::create).executeAsOneOrNull();
return mapSingleRow(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
} }
public List<UnifiedKeyInfo> getUnifiedKeyInfo(long... masterKeyIds) { public List<UnifiedKeyInfo> getUnifiedKeyInfo(long... masterKeyIds) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyIds(masterKeyIds); return keysQueries.selectUnifiedKeyInfoByMasterKeyIds(getLongArrayAsList(masterKeyIds), UnifiedKeyInfo::create)
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER); .executeAsList();
} }
public List<UnifiedKeyInfo> getUnifiedKeyInfosByMailAddress(String mailAddress) { public List<UnifiedKeyInfo> getUnifiedKeyInfosByMailAddress(String mailAddress) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%'); return keysQueries.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%', UnifiedKeyInfo::create)
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER); .executeAsList();
} }
public List<UnifiedKeyInfo> getAllUnifiedKeyInfo() { public List<UnifiedKeyInfo> getAllUnifiedKeyInfo() {
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfo(); return keysQueries.selectAllUnifiedKeyInfo(UnifiedKeyInfo::create).executeAsList();
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
} }
public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithSecret() { public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithSecret() {
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfoWithSecret(); return keysQueries.selectAllUnifiedKeyInfoWithSecret(UnifiedKeyInfo::create).executeAsList();
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
} }
public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithAuthKeySecret() { public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithAuthKeySecret() {
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfoWithAuthKeySecret(); return keysQueries.selectAllUnifiedKeyInfoWithAuthKeySecret(UnifiedKeyInfo::create).executeAsList();
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
} }
public List<UserId> getUserIds(long... masterKeyIds) { public List<UserId> getUserIds(long... masterKeyIds) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyIds); return getDatabase().getUserPacketsQueries()
return mapAllRows(query, UserPacket.USER_ID_MAPPER); .selectUserIdsByMasterKeyId(getLongArrayAsList(masterKeyIds), UserId::create).executeAsList();
} }
public List<String> getConfirmedUserIds(long masterKeyId) { public List<String> getConfirmedUserIds(long masterKeyId) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyIdAndVerification( return getDatabase().getUserPacketsQueries()
Certification.FACTORY, masterKeyId, VerificationStatus.VERIFIED_SECRET); .selectUserIdsByMasterKeyIdAndVerification(masterKeyId,
return mapAllRows(query, cursor -> UserPacket.USER_ID_MAPPER.map(cursor).user_id()); VerificationStatus.VERIFIED_SECRET, (
master_key_id,
rank,
user_id,
name,
email,
comment,
is_primary,
is_revoked,
verified_int
) -> user_id).executeAsList();
} }
public List<SubKey> getSubKeysByMasterKeyId(long masterKeyId) { public List<Keys> getSubKeysByMasterKeyId(long masterKeyId) {
SqlDelightQuery query = SubKey.FACTORY.selectSubkeysByMasterKeyId(masterKeyId); return keysQueries.selectSubkeysByMasterKeyId(masterKeyId).executeAsList();
return mapAllRows(query, SubKey.SUBKEY_MAPPER);
} }
public SecretKeyType getSecretKeyType(long keyId) throws NotFoundException { public SecretKeyType getSecretKeyType(long keyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectSecretKeyType(keyId); try {
return mapSingleRowOrThrow(query, SubKey.SKT_MAPPER); return keysQueries.selectSecretKeyType(keyId).executeAsOne();
} catch (NullPointerException npe) {
throw new NotFoundException();
}
} }
public byte[] getFingerprintByKeyId(long keyId) throws NotFoundException { public byte[] getFingerprintByKeyId(long keyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectFingerprintByKeyId(keyId); try {
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectFingerprintByKeyIdMapper()); return keysQueries.selectFingerprintByKeyId(keyId).executeAsOne();
} catch (NullPointerException npe) {
throw new NotFoundException();
}
} }
private byte[] getKeyRingAsArmoredData(byte[] data) throws IOException { private byte[] getKeyRingAsArmoredData(byte[] data) throws IOException {
@@ -205,23 +223,26 @@ public class KeyRepository extends AbstractDao {
return bos.toByteArray(); return bos.toByteArray();
} }
public String getPublicKeyRingAsArmoredString(long masterKeyId) throws NotFoundException, IOException { public String getPublicKeyRingAsArmoredString(long masterKeyId)
throws NotFoundException, IOException {
byte[] data = loadPublicKeyRingData(masterKeyId); byte[] data = loadPublicKeyRingData(masterKeyId);
byte[] armoredData = getKeyRingAsArmoredData(data); byte[] armoredData = getKeyRingAsArmoredData(data);
return new String(armoredData); return new String(armoredData);
} }
public byte[] getSecretKeyRingAsArmoredData(long masterKeyId) throws NotFoundException, IOException { public byte[] getSecretKeyRingAsArmoredData(long masterKeyId)
throws NotFoundException, IOException {
byte[] data = loadSecretKeyRingData(masterKeyId); byte[] data = loadSecretKeyRingData(masterKeyId);
return getKeyRingAsArmoredData(data); return getKeyRingAsArmoredData(data);
} }
public final byte[] loadPublicKeyRingData(long masterKeyId) throws NotFoundException { public final byte[] loadPublicKeyRingData(long masterKeyId) throws NotFoundException {
SqlDelightQuery query = KeyRingPublic.FACTORY.selectByMasterKeyId(masterKeyId); Query<Keyrings_public> keyringsPublicQuery =
try (Cursor cursor = getReadableDb().query(query)) { keyRingsPublicQueries.selectByMasterKeyId(masterKeyId);
if (cursor.moveToFirst()) { try (SqlCursor cursor = keyringsPublicQuery.execute()) {
KeyRingPublic keyRingPublic = KeyRingPublic.MAPPER.map(cursor); if (cursor.next()) {
byte[] keyRingData = keyRingPublic.key_ring_data(); Keyrings_public keyRingPublic = keyringsPublicQuery.getMapper().invoke(cursor);
byte[] keyRingData = keyRingPublic.getKey_ring_data();
if (keyRingData == null) { if (keyRingData == null) {
keyRingData = mLocalPublicKeyStorage.readPublicKey(masterKeyId); keyRingData = mLocalPublicKeyStorage.readPublicKey(masterKeyId);
} }
@@ -243,18 +264,16 @@ public class KeyRepository extends AbstractDao {
} }
public long getSecretSignId(long masterKeyId) throws NotFoundException { public long getSecretSignId(long masterKeyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyId(masterKeyId); return keysQueries.selectEffectiveSignKeyIdByMasterKeyId(masterKeyId).executeAsOneOrNull();
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyIdMapper());
} }
public long getEffectiveAuthenticationKeyId(long masterKeyId) throws NotFoundException { public long getEffectiveAuthenticationKeyId(long masterKeyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyId(masterKeyId); return keysQueries.selectEffectiveAuthKeyIdByMasterKeyId(masterKeyId).executeAsOneOrNull();
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyIdMapper());
} }
public List<Long> getPublicEncryptionIds(long masterKeyId) { public List<Long> getPublicEncryptionIds(long masterKeyId) {
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveEncryptionKeyIdsByMasterKeyId(masterKeyId); return keysQueries.selectEffectiveEncryptionKeyIdsByMasterKeyId(masterKeyId)
return mapAllRows(query, SubKey.FACTORY.selectEffectiveEncryptionKeyIdsByMasterKeyIdMapper()); .executeAsList();
} }
public static class NotFoundException extends Exception { public static class NotFoundException extends Exception {
@@ -274,4 +293,13 @@ public class KeyRepository extends AbstractDao {
} }
return longs; return longs;
} }
private List<Long> getLongArrayAsList(long[] longList) {
Long[] longs = new Long[longList.length];
int i = 0;
for (Long aLong : longList) {
longs[i++] = aLong;
}
return Arrays.asList(longs);
}
} }

View File

@@ -25,24 +25,23 @@ import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import androidx.sqlite.db.SupportSQLiteDatabase;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.collection.LongSparseArray; import androidx.collection.LongSparseArray;
import androidx.sqlite.db.SupportSQLiteDatabase;
import org.openintents.openpgp.util.OpenPgpUtils; import org.openintents.openpgp.util.OpenPgpUtils;
import org.sufficientlysecure.keychain.KeyRingsPublicModel.DeleteByMasterKeyId; import org.sufficientlysecure.keychain.Certs;
import org.sufficientlysecure.keychain.Key_signatures;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.KeysModel.UpdateHasSecretByKeyId; import org.sufficientlysecure.keychain.Keyrings_public;
import org.sufficientlysecure.keychain.KeysModel.UpdateHasSecretByMasterKeyId; import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.KeysQueries;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.User_packets;
import org.sufficientlysecure.keychain.UtilQueries;
import org.sufficientlysecure.keychain.daos.DatabaseBatchInteractor.BatchOp; import org.sufficientlysecure.keychain.daos.DatabaseBatchInteractor.BatchOp;
import org.sufficientlysecure.keychain.model.Certification; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.KeyRingPublic;
import org.sufficientlysecure.keychain.model.KeySignature;
import org.sufficientlysecure.keychain.model.SubKey;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.UserPacket;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
@@ -114,7 +113,7 @@ public class KeyWritableRepository extends KeyRepository {
this.context = context; this.context = context;
this.databaseNotifyManager = databaseNotifyManager; this.databaseNotifyManager = databaseNotifyManager;
this.autocryptPeerDao = autocryptPeerDao; this.autocryptPeerDao = autocryptPeerDao;
this.databaseBatchInteractor = new DatabaseBatchInteractor(getWritableDb()); this.databaseBatchInteractor = new DatabaseBatchInteractor(getDatabase());
} }
private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() { private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() {
@@ -193,7 +192,7 @@ public class KeyWritableRepository extends KeyRepository {
log(LogType.MSG_IP_INSERT_KEYRING); log(LogType.MSG_IP_INSERT_KEYRING);
byte[] encodedRingIfDbCachable = encodedKeyRing.length < MAX_CACHED_KEY_SIZE ? encodedKeyRing : null; byte[] encodedRingIfDbCachable = encodedKeyRing.length < MAX_CACHED_KEY_SIZE ? encodedKeyRing : null;
KeyRingPublic keyRingPublic = KeyRingPublic.create(masterKeyId, encodedRingIfDbCachable); Keyrings_public keyRingPublic = new Keyrings_public(masterKeyId, encodedRingIfDbCachable);
operations.add(DatabaseBatchInteractor.createInsertKeyRingPublic(keyRingPublic)); operations.add(DatabaseBatchInteractor.createInsertKeyRingPublic(keyRingPublic));
log(LogType.MSG_IP_INSERT_SUBKEYS); log(LogType.MSG_IP_INSERT_SUBKEYS);
@@ -239,9 +238,12 @@ public class KeyWritableRepository extends KeyRepository {
} }
} }
SubKey subKey = SubKey.create(masterKeyId, rank, key.getKeyId(), long creationUnixTime = creation.getTime() / 1000;
Long expiryUnixTime = expiry != null ? expiry.getTime() / 1000 : null;
long validFromTime = bindingSignatureTime.getTime() / 1000;
Keys subKey = new Keys(masterKeyId, rank, key.getKeyId(),
key.getBitStrength(), key.getCurveOid(), key.getAlgorithm(), key.getFingerprint(), key.getBitStrength(), key.getCurveOid(), key.getAlgorithm(), key.getFingerprint(),
c, s, e, a, key.isRevoked(), SecretKeyType.UNAVAILABLE, key.isSecure(), creation, expiry, bindingSignatureTime); c, s, e, a, key.isRevoked(), SecretKeyType.UNAVAILABLE, key.isSecure(), creationUnixTime, expiryUnixTime, validFromTime);
operations.add(DatabaseBatchInteractor.createInsertSubKey(subKey)); operations.add(DatabaseBatchInteractor.createInsertSubKey(subKey));
++rank; ++rank;
@@ -300,7 +302,7 @@ public class KeyWritableRepository extends KeyRepository {
// keep a note about the issuer of this key signature // keep a note about the issuer of this key signature
if (!signerKeyIds.contains(certId)) { if (!signerKeyIds.contains(certId)) {
KeySignature keySignature = KeySignature.create(masterKeyId, certId); Key_signatures keySignature = new Key_signatures(masterKeyId, certId);
operations.add(DatabaseBatchInteractor.createInsertSignerKey(keySignature)); operations.add(DatabaseBatchInteractor.createInsertSignerKey(keySignature));
signerKeyIds.add(certId); signerKeyIds.add(certId);
} }
@@ -468,7 +470,7 @@ public class KeyWritableRepository extends KeyRepository {
for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) { for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) {
UserPacketItem item = uids.get(userIdRank); UserPacketItem item = uids.get(userIdRank);
Long type = item.type != null ? item.type.longValue() : null; Long type = item.type != null ? item.type.longValue() : null;
UserPacket userPacket = UserPacket.create(masterKeyId, userIdRank, type, item.userId, item.name, item.email, User_packets userPacket = new User_packets(masterKeyId, userIdRank, type, item.userId, item.name, item.email,
item.comment, item.attributeData, item.isPrimary, item.selfRevocation != null); item.comment, item.attributeData, item.isPrimary, item.selfRevocation != null);
operations.add(DatabaseBatchInteractor.createInsertUserPacket(userPacket)); operations.add(DatabaseBatchInteractor.createInsertUserPacket(userPacket));
@@ -508,14 +510,13 @@ public class KeyWritableRepository extends KeyRepository {
mIndent -= 1; mIndent -= 1;
} }
SupportSQLiteDatabase db = databaseBatchInteractor.getDb(); SupportSQLiteDatabase db = getWritableDb();
try { try {
db.beginTransaction(); db.beginTransaction();
// delete old version of this keyRing (from database only!), which also deletes all keys and userIds on cascade // delete old version of this keyRing (from database only!), which also deletes all keys and userIds on cascade
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(db); getDatabase().getKeyRingsPublicQueries().deleteByMasterKeyId(masterKeyId);
deleteStatement.bind(masterKeyId); int deletedRows = getDatabase().getUtilQueries().selectChanges().executeAsOne().intValue();
int deletedRows = deleteStatement.executeUpdateDelete();
if (deletedRows > 0) { if (deletedRows > 0) {
log(LogType.MSG_IP_DELETE_OLD_OK); log(LogType.MSG_IP_DELETE_OLD_OK);
@@ -559,9 +560,8 @@ public class KeyWritableRepository extends KeyRepository {
} }
autocryptPeerDao.deleteByMasterKeyId(masterKeyId); autocryptPeerDao.deleteByMasterKeyId(masterKeyId);
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(getWritableDb()); getDatabase().getKeyRingsPublicQueries().deleteByMasterKeyId(masterKeyId);
deleteStatement.bind(masterKeyId); int deletedRows = getDatabase().getUtilQueries().selectChanges().executeAsOne().intValue();
int deletedRows = deleteStatement.executeUpdateDelete();
databaseNotifyManager.notifyKeyChange(masterKeyId); databaseNotifyManager.notifyKeyChange(masterKeyId);
@@ -631,12 +631,10 @@ public class KeyWritableRepository extends KeyRepository {
} }
{ {
UpdateHasSecretByMasterKeyId resetStatement = KeysQueries keysQueries = getDatabase().getKeysQueries();
SubKey.createUpdateHasSecretByMasterKeyIdStatement(getWritableDb()); UtilQueries utilQueries = getDatabase().getUtilQueries();
resetStatement.bind(masterKeyId, SecretKeyType.GNU_DUMMY);
resetStatement.executeUpdateDelete();
UpdateHasSecretByKeyId updateStatement = SubKey.createUpdateHasSecretByKeyId(getWritableDb()); keysQueries.updateHasSecretByMasterKeyId(masterKeyId, SecretKeyType.GNU_DUMMY);
// then, mark exactly the keys we have available // then, mark exactly the keys we have available
log(LogType.MSG_IS_IMPORTING_SUBKEYS); log(LogType.MSG_IS_IMPORTING_SUBKEYS);
@@ -644,8 +642,8 @@ public class KeyWritableRepository extends KeyRepository {
for (CanonicalizedSecretKey sub : keyRing.secretKeyIterator()) { for (CanonicalizedSecretKey sub : keyRing.secretKeyIterator()) {
long id = sub.getKeyId(); long id = sub.getKeyId();
SecretKeyType mode = sub.getSecretKeyTypeSuperExpensive(); SecretKeyType mode = sub.getSecretKeyTypeSuperExpensive();
updateStatement.bind(id, mode); keysQueries.updateHasSecretByKeyId(id, mode);
int upd = updateStatement.executeUpdateDelete(); int upd = utilQueries.selectChanges().executeAsOne().intValue();
if (upd == 1) { if (upd == 1) {
switch (mode) { switch (mode) {
case PASSPHRASE: case PASSPHRASE:
@@ -1013,8 +1011,9 @@ public class KeyWritableRepository extends KeyRepository {
private BatchOp buildCertOperations(long masterKeyId, int rank, WrappedSignature cert, VerificationStatus verificationStatus) { private BatchOp buildCertOperations(long masterKeyId, int rank, WrappedSignature cert, VerificationStatus verificationStatus) {
try { try {
Certification certification = Certification.create(masterKeyId, rank, cert.getKeyId(), long creationUnixTime = cert.getCreationTime().getTime() / 1000;
cert.getSignatureType(), verificationStatus, cert.getCreationTime(), cert.getEncoded()); Certs certification = new Certs(masterKeyId, rank, cert.getKeyId(),
cert.getSignatureType(), verificationStatus, creationUnixTime, cert.getEncoded());
return DatabaseBatchInteractor.createInsertCertification(certification); return DatabaseBatchInteractor.createInsertCertification(certification);
} catch (IOException e) { } catch (IOException e) {
throw new AssertionError(e); throw new AssertionError(e);

View File

@@ -20,11 +20,7 @@ package org.sufficientlysecure.keychain.daos;
import android.content.Context; import android.content.Context;
import com.squareup.sqldelight.SqlDelightQuery;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.OverriddenWarningsModel.DeleteByIdentifier;
import org.sufficientlysecure.keychain.OverriddenWarningsModel.InsertIdentifier;
import org.sufficientlysecure.keychain.model.OverriddenWarning;
public class OverriddenWarningsDao extends AbstractDao { public class OverriddenWarningsDao extends AbstractDao {
@@ -35,25 +31,21 @@ public class OverriddenWarningsDao extends AbstractDao {
return new OverriddenWarningsDao(database, databaseNotifyManager); return new OverriddenWarningsDao(database, databaseNotifyManager);
} }
private OverriddenWarningsDao(KeychainDatabase db, DatabaseNotifyManager databaseNotifyManager) { private OverriddenWarningsDao(KeychainDatabase db,
DatabaseNotifyManager databaseNotifyManager) {
super(db, databaseNotifyManager); super(db, databaseNotifyManager);
} }
public boolean isWarningOverridden(String identifier) { public boolean isWarningOverridden(String identifier) {
SqlDelightQuery query = OverriddenWarning.FACTORY.selectCountByIdentifier(identifier); return getDatabase().getOverriddenWarningsQueries().selectCountByIdentifier(identifier)
Long result = mapSingleRow(query, OverriddenWarning.FACTORY.selectCountByIdentifierMapper()::map); .executeAsOne() > 0;
return result != null && result > 0;
} }
public void putOverride(String identifier) { public void putOverride(String identifier) {
InsertIdentifier statement = new InsertIdentifier(getWritableDb()); getDatabase().getOverriddenWarningsQueries().insertIdentifier(identifier);
statement.bind(identifier);
statement.executeInsert();
} }
public void deleteOverride(String identifier) { public void deleteOverride(String identifier) {
DeleteByIdentifier statement = new DeleteByIdentifier(getWritableDb()); getDatabase().getOverriddenWarningsQueries().deleteByIdentifier(identifier);
statement.bind(identifier);
statement.executeInsert();
} }
} }

View File

@@ -1,16 +1,19 @@
package org.sufficientlysecure.keychain.daos; package org.sufficientlysecure.keychain.daos;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import android.content.Context; import android.content.Context;
import android.database.Cursor;
import com.squareup.sqldelight.SqlDelightQuery; import com.squareup.sqldelight.Query;
import com.squareup.sqldelight.db.SqlCursor;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.model.UserPacket; import org.sufficientlysecure.keychain.UidStatus;
import org.sufficientlysecure.keychain.model.UserPacket.UidStatus; import org.sufficientlysecure.keychain.model.UserId;
public class UserIdDao extends AbstractDao { public class UserIdDao extends AbstractDao {
@@ -25,20 +28,38 @@ public class UserIdDao extends AbstractDao {
super(db, databaseNotifyManager); super(db, databaseNotifyManager);
} }
public UidStatus getUidStatusByEmailLike(String emailLike) { public List<UserId> getUserIdsByMasterKeyIds(long... masterKeyIds) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdStatusByEmailLike(emailLike); return getDatabase().getUserPacketsQueries()
return mapSingleRow(query, UserPacket.UID_STATUS_MAPPER); .selectUserIdsByMasterKeyId(getLongArrayAsList(masterKeyIds), UserId::create)
.executeAsList();
} }
public Map<String,UidStatus> getUidStatusByEmail(String... emails) { public UidStatus getUidStatusByEmailLike(String emailLike) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdStatusByEmail(emails); return getDatabase().getUserPacketsQueries().selectUserIdStatusByEmailLike(emailLike)
Map<String,UidStatus> result = new HashMap<>(); .executeAsOne();
try (Cursor cursor = getReadableDb().query(query)) { }
while (cursor.moveToNext()) {
UidStatus item = UserPacket.UID_STATUS_MAPPER.map(cursor); public Map<String, UidStatus> getUidStatusByEmail(String... emails) {
result.put(item.email(), item); Query<UidStatus> q = getDatabase().getUserPacketsQueries()
.selectUserIdStatusByEmail(Arrays.asList(emails));
Map<String, UidStatus> result = new HashMap<>();
try (SqlCursor cursor = q.execute()) {
while (cursor.next()) {
UidStatus item = q.getMapper().invoke(cursor);
result.put(item.getEmail(), item);
} }
} catch (IOException e) {
// oops
} }
return result; return result;
} }
}
private List<Long> getLongArrayAsList(long[] longList) {
Long[] longs = new Long[longList.length];
int i = 0;
for (Long aLong : longList) {
longs[i++] = aLong;
}
return Arrays.asList(longs);
}
}

View File

@@ -10,11 +10,11 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import org.sufficientlysecure.keychain.Api_apps;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.ApiAppDao; import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager; import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
import org.sufficientlysecure.keychain.livedata.ApiAppsLiveData.ListedApp; import org.sufficientlysecure.keychain.livedata.ApiAppsLiveData.ListedApp;
import org.sufficientlysecure.keychain.model.ApiApp;
import org.sufficientlysecure.keychain.ui.keyview.loader.AsyncTaskLiveData; import org.sufficientlysecure.keychain.ui.keyview.loader.AsyncTaskLiveData;
@@ -41,18 +41,18 @@ public class ApiAppsLiveData extends AsyncTaskLiveData<List<ListedApp>> {
} }
private void loadRegisteredApps(ArrayList<ListedApp> result) { private void loadRegisteredApps(ArrayList<ListedApp> result) {
List<ApiApp> registeredApiApps = apiAppDao.getAllApiApps(); List<Api_apps> registeredApiApps = apiAppDao.getAllApiApps();
for (ApiApp apiApp : registeredApiApps) { for (Api_apps apiApp : registeredApiApps) {
ListedApp listedApp; ListedApp listedApp;
try { try {
ApplicationInfo ai = packageManager.getApplicationInfo(apiApp.package_name(), 0); ApplicationInfo ai = packageManager.getApplicationInfo(apiApp.getPackage_name(), 0);
CharSequence applicationLabel = packageManager.getApplicationLabel(ai); CharSequence applicationLabel = packageManager.getApplicationLabel(ai);
Drawable applicationIcon = packageManager.getApplicationIcon(ai); Drawable applicationIcon = packageManager.getApplicationIcon(ai);
listedApp = new ListedApp(apiApp.package_name(), true, true, applicationLabel, applicationIcon, null); listedApp = new ListedApp(apiApp.getPackage_name(), true, true, applicationLabel, applicationIcon, null);
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
listedApp = new ListedApp(apiApp.package_name(), false, true, apiApp.package_name(), null, null); listedApp = new ListedApp(apiApp.getPackage_name(), false, true, apiApp.getPackage_name(), null, null);
} }
result.add(listedApp); result.add(listedApp);
} }

View File

@@ -1,11 +0,0 @@
package org.sufficientlysecure.keychain.model;
import com.google.auto.value.AutoValue;
import org.sufficientlysecure.keychain.ApiAllowedKeysModel;
@AutoValue
public abstract class ApiAllowedKey implements ApiAllowedKeysModel {
public static final Factory<ApiAllowedKey> FACTORY = new Factory<ApiAllowedKey>(AutoValue_ApiAllowedKey::new);
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright (C) 2017 Schürmann & Breitmoser GbR
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.model;
import com.google.auto.value.AutoValue;
import org.sufficientlysecure.keychain.ApiAppsModel;
@AutoValue
public abstract class ApiApp implements ApiAppsModel {
public static final ApiAppsModel.Factory<ApiApp> FACTORY =
new ApiAppsModel.Factory<ApiApp>(AutoValue_ApiApp::new);
public static ApiApp create(String packageName, byte[] packageSignature) {
return new AutoValue_ApiApp(null, packageName, packageSignature);
}
}

View File

@@ -1,57 +0,0 @@
package org.sufficientlysecure.keychain.model;
import com.google.auto.value.AutoValue;
import com.squareup.sqldelight.RowMapper;
import org.sufficientlysecure.keychain.AutocryptPeersModel;
@AutoValue
public abstract class AutocryptPeer implements AutocryptPeersModel {
public enum GossipOrigin {
GOSSIP_HEADER, SIGNATURE, DEDUP
}
public static final Factory<AutocryptPeer> FACTORY = new Factory<AutocryptPeer>(AutoValue_AutocryptPeer::new,
CustomColumnAdapters.DATE_ADAPTER, CustomColumnAdapters.DATE_ADAPTER, CustomColumnAdapters.DATE_ADAPTER,
CustomColumnAdapters.GOSSIP_ORIGIN_ADAPTER);
public static final RowMapper<AutocryptPeer> PEER_MAPPER = FACTORY.selectByIdentifiersMapper();
public static final RowMapper<AutocryptKeyStatus> KEY_STATUS_MAPPER =
FACTORY.selectAutocryptKeyStatusMapper(AutoValue_AutocryptPeer_AutocryptKeyStatus::new);
@AutoValue
public static abstract class AutocryptKeyStatus implements SelectAutocryptKeyStatusModel<AutocryptPeer> {
public boolean hasGossipKey() {
return autocryptPeer().gossip_master_key_id() != null;
}
public boolean isGossipKeyRevoked() {
Boolean gossip_key_is_revoked = gossip_key_is_revoked_int();
return gossip_key_is_revoked != null && gossip_key_is_revoked;
}
public boolean isGossipKeyExpired() {
return gossip_key_is_expired_int() != 0;
}
public boolean isGossipKeyVerified() {
return gossip_key_is_verified_int() != 0;
}
public boolean isKeyRevoked() {
Boolean revoked = key_is_revoked_int();
return revoked != null && revoked;
}
public boolean isKeyExpired() {
return key_is_expired_int() != 0;
}
public boolean isKeyVerified() {
return key_is_verified_int() != 0;
}
}
}

View File

@@ -1,39 +0,0 @@
package org.sufficientlysecure.keychain.model;
import java.util.Date;
import androidx.sqlite.db.SupportSQLiteDatabase;
import com.google.auto.value.AutoValue;
import org.sufficientlysecure.keychain.CertsModel;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
@AutoValue
public abstract class Certification implements CertsModel {
public static final CertsModel.Factory<Certification> FACTORY =
new CertsModel.Factory<>(AutoValue_Certification::new, CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER);
public static final SelectVerifyingCertDetailsMapper<CertDetails> CERT_DETAILS_MAPPER =
new SelectVerifyingCertDetailsMapper<>(AutoValue_Certification_CertDetails::new);
public static Certification create(long masterKeyId, long rank, long keyIdCertifier, long type,
VerificationStatus verified, Date creation, byte[] data) {
long creationUnixTime = creation.getTime() / 1000;
return new AutoValue_Certification(masterKeyId, rank, keyIdCertifier, type, verified, creationUnixTime, data);
}
public static InsertCert createInsertStatement(SupportSQLiteDatabase db) {
return new InsertCert(db, FACTORY);
}
public void bindTo(InsertCert statement) {
statement.bind(master_key_id(), rank(), key_id_certifier(), type(), verified(), creation(), data());
}
@AutoValue
public static abstract class CertDetails implements CertsModel.SelectVerifyingCertDetailsModel {
}
}

View File

@@ -4,9 +4,7 @@ package org.sufficientlysecure.keychain.model;
import java.util.Date; import java.util.Date;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.squareup.sqldelight.ColumnAdapter; import com.squareup.sqldelight.ColumnAdapter;
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
@@ -15,7 +13,7 @@ public final class CustomColumnAdapters {
private CustomColumnAdapters() { } private CustomColumnAdapters() { }
static final ColumnAdapter<Date,Long> DATE_ADAPTER = new ColumnAdapter<Date,Long>() { public static final ColumnAdapter<Date,Long> DATE_ADAPTER = new ColumnAdapter<Date,Long>() {
@NonNull @NonNull
@Override @Override
public Date decode(Long databaseValue) { public Date decode(Long databaseValue) {
@@ -29,7 +27,7 @@ public final class CustomColumnAdapters {
} }
}; };
static final ColumnAdapter<GossipOrigin,Long> GOSSIP_ORIGIN_ADAPTER = new ColumnAdapter<GossipOrigin,Long>() { public static final ColumnAdapter<GossipOrigin,Long> GOSSIP_ORIGIN_ADAPTER = new ColumnAdapter<GossipOrigin,Long>() {
@NonNull @NonNull
@Override @Override
public GossipOrigin decode(Long databaseValue) { public GossipOrigin decode(Long databaseValue) {

View File

@@ -0,0 +1,5 @@
package org.sufficientlysecure.keychain.model;
public enum GossipOrigin {
GOSSIP_HEADER, SIGNATURE, DEDUP
}

View File

@@ -1,24 +0,0 @@
package org.sufficientlysecure.keychain.model;
import com.google.auto.value.AutoValue;
import org.sufficientlysecure.keychain.KeyMetadataModel;
@AutoValue
public abstract class KeyMetadata implements KeyMetadataModel {
public static final Factory<KeyMetadata> FACTORY = new Factory<>(
AutoValue_KeyMetadata::new, CustomColumnAdapters.DATE_ADAPTER);
public boolean hasBeenUpdated() {
return last_updated() != null;
}
public boolean isPublished() {
if (last_updated() == null) {
throw new IllegalStateException("Cannot get publication state if key has never been updated!");
}
Boolean seenOnKeyservers = seen_on_keyservers();
return seenOnKeyservers != null && seenOnKeyservers;
}
}

View File

@@ -1,27 +0,0 @@
package org.sufficientlysecure.keychain.model;
import androidx.sqlite.db.SupportSQLiteDatabase;
import com.google.auto.value.AutoValue;
import org.sufficientlysecure.keychain.KeyRingsPublicModel;
@AutoValue
public abstract class KeyRingPublic implements KeyRingsPublicModel {
public static final Factory<KeyRingPublic> FACTORY = new Factory<>(AutoValue_KeyRingPublic::new);
public static final Mapper<KeyRingPublic> MAPPER = new Mapper<>(FACTORY);
public static KeyRingPublic create(long masterKeyId, byte[] keyRingData) {
return new AutoValue_KeyRingPublic(masterKeyId, keyRingData);
}
public static InsertKeyRingPublic createInsertStatement(SupportSQLiteDatabase db) {
return new InsertKeyRingPublic(db);
}
public void bindTo(InsertKeyRingPublic statement) {
statement.bind(master_key_id(), key_ring_data());
}
}

View File

@@ -1,27 +0,0 @@
package org.sufficientlysecure.keychain.model;
import androidx.sqlite.db.SupportSQLiteDatabase;
import com.google.auto.value.AutoValue;
import org.sufficientlysecure.keychain.KeySignaturesModel;
@AutoValue
public abstract class KeySignature implements KeySignaturesModel {
public static final Factory<KeySignature> FACTORY = new Factory<>(AutoValue_KeySignature::new);
public static final Mapper<KeySignature> MAPPER = new Mapper<>(FACTORY);
public static InsertKeySignature createInsertStatement(SupportSQLiteDatabase db) {
return new InsertKeySignature(db);
}
public void bindTo(InsertKeySignature statement) {
statement.bind(master_key_id(), signer_key_id());
}
public static KeySignature create(long masterKeyId, long certId) {
return new AutoValue_KeySignature(masterKeyId, certId);
}
}

View File

@@ -1,14 +0,0 @@
package org.sufficientlysecure.keychain.model;
import com.google.auto.value.AutoValue;
import org.sufficientlysecure.keychain.KeySignaturesModel;
import org.sufficientlysecure.keychain.OverriddenWarningsModel;
@AutoValue
public abstract class OverriddenWarning implements OverriddenWarningsModel {
public static final Factory<OverriddenWarning> FACTORY = new Factory<>(AutoValue_OverriddenWarning::new);
public static final Mapper<OverriddenWarning> MAPPER = new Mapper<>(FACTORY);
}

View File

@@ -1,116 +0,0 @@
package org.sufficientlysecure.keychain.model;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import androidx.sqlite.db.SupportSQLiteDatabase;
import com.google.auto.value.AutoValue;
import com.squareup.sqldelight.RowMapper;
import org.sufficientlysecure.keychain.KeysModel;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
@AutoValue
public abstract class SubKey implements KeysModel {
public static final Factory<SubKey> FACTORY =
new Factory<>(AutoValue_SubKey::new, CustomColumnAdapters.SECRET_KEY_TYPE_ADAPTER);
public static final UnifiedKeyViewMapper<UnifiedKeyInfo, Certification> UNIFIED_KEY_INFO_MAPPER =
FACTORY.selectAllUnifiedKeyInfoMapper(
AutoValue_SubKey_UnifiedKeyInfo::new, Certification.FACTORY);
public static Mapper<SubKey> SUBKEY_MAPPER = new Mapper<>(FACTORY);
public static RowMapper<SecretKeyType> SKT_MAPPER = FACTORY.selectSecretKeyTypeMapper();
public boolean expires() {
return expiry() != null;
}
public static SubKey create(long masterKeyId, long rank, long keyId, Integer keySize, String keyCurveOid,
int algorithm, byte[] fingerprint, boolean canCertify, boolean canSign, boolean canEncrypt, boolean canAuth,
boolean isRevoked, SecretKeyType hasSecret, boolean isSecure, Date creation, Date expiry,
Date validFrom) {
long creationUnixTime = creation.getTime() / 1000;
Long expiryUnixTime = expiry != null ? expiry.getTime() / 1000 : null;
long validFromTime = validFrom.getTime() / 1000;
return new AutoValue_SubKey(masterKeyId, rank, keyId, keySize, keyCurveOid, algorithm, fingerprint, canCertify,
canSign, canEncrypt, canAuth, isRevoked, hasSecret, isSecure, creationUnixTime, expiryUnixTime, validFromTime);
}
public static InsertKey createInsertStatement(SupportSQLiteDatabase db) {
return new InsertKey(db, FACTORY);
}
public static UpdateHasSecretByMasterKeyId createUpdateHasSecretByMasterKeyIdStatement(SupportSQLiteDatabase db) {
return new UpdateHasSecretByMasterKeyId(db, FACTORY);
}
public static UpdateHasSecretByKeyId createUpdateHasSecretByKeyId(SupportSQLiteDatabase db) {
return new UpdateHasSecretByKeyId(db, FACTORY);
}
public void bindTo(InsertKey statement) {
statement.bind(master_key_id(), rank(), key_id(), key_size(), key_curve_oid(), algorithm(), fingerprint(),
can_certify(), can_sign(), can_encrypt(), can_authenticate(), is_revoked(), has_secret(), is_secure(),
creation(), expiry(), validFrom());
}
@AutoValue
public static abstract class UnifiedKeyInfo implements KeysModel.UnifiedKeyViewModel {
private List<String> autocryptPackageNames;
private String cachedUidSearchString;
public boolean is_expired() {
Long expiry = expiry();
return expiry != null && expiry * 1000 < System.currentTimeMillis();
}
public boolean has_any_secret() {
return has_any_secret_int() != 0;
}
public boolean is_verified() {
VerificationStatus verified = verified();
return verified != null && verified == VerificationStatus.VERIFIED_SECRET;
}
public boolean has_duplicate() {
return has_duplicate_int() != 0;
}
public List<String> autocrypt_package_names() {
if (autocryptPackageNames == null) {
String csv = autocrypt_package_names_csv();
autocryptPackageNames = csv == null ? Collections.emptyList() :
Arrays.asList(csv.split(","));
}
return autocryptPackageNames;
}
public boolean has_auth_key() {
return has_auth_key_int() != 0;
}
public boolean has_encrypt_key() {
return has_encrypt_key_int() != 0;
}
public boolean has_sign_key() {
return has_sign_key_int() != 0;
}
public String uidSearchString() {
if (cachedUidSearchString == null) {
cachedUidSearchString = user_id_list();
if (cachedUidSearchString == null) {
cachedUidSearchString = "";
}
cachedUidSearchString = cachedUidSearchString.toLowerCase();
}
return cachedUidSearchString;
}
}
}

View File

@@ -0,0 +1,108 @@
package org.sufficientlysecure.keychain.model;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import androidx.annotation.Nullable;
import com.google.auto.value.AutoValue;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
@AutoValue
public abstract class UnifiedKeyInfo {
public static UnifiedKeyInfo create(long master_key_id, byte[] fingerprint, Long min,
String user_id, String name, String email, String comment, long creation, Long expiry,
boolean is_revoked, boolean is_secure, boolean can_certify,
CanonicalizedKeyRing.VerificationStatus verified, boolean has_duplicate,
boolean has_any_secret, boolean has_encrypt_key, boolean has_sign_key,
boolean has_auth_key, String autocrypt_package_names_csv, String user_id_list) {
return new AutoValue_UnifiedKeyInfo(master_key_id, fingerprint, min, user_id, name, email,
comment, creation, expiry, is_revoked, is_secure, can_certify, verified,
has_duplicate, has_any_secret, has_encrypt_key, has_sign_key, has_auth_key,
autocrypt_package_names_csv, user_id_list);
}
private List<String> autocryptPackageNames;
private String cachedUidSearchString;
public abstract long master_key_id();
public abstract byte[] fingerprint();
@Nullable
public abstract Long min();
public abstract String user_id();
@Nullable
public abstract String name();
@Nullable
public abstract String email();
@Nullable
public abstract String comment();
public abstract long creation();
@Nullable
public abstract Long expiry();
public abstract boolean is_revoked();
public abstract boolean is_secure();
public abstract boolean can_certify();
@Nullable
public abstract VerificationStatus verified();
public abstract boolean has_duplicate();
public abstract boolean has_any_secret();
public abstract boolean has_encrypt_key();
public abstract boolean has_sign_key();
public abstract boolean has_auth_key();
@Nullable
public abstract String autocrypt_package_names_csv();
@Nullable
public abstract String user_id_list();
public boolean is_expired() {
Long expiry = expiry();
return expiry != null && expiry * 1000 < System.currentTimeMillis();
}
public boolean is_verified() {
VerificationStatus verified = verified();
return verified != null && verified == VerificationStatus.VERIFIED_SECRET;
}
public List<String> autocrypt_package_names() {
if (autocryptPackageNames == null) {
String csv = autocrypt_package_names_csv();
autocryptPackageNames =
csv == null ? Collections.emptyList() : Arrays.asList(csv.split(","));
}
return autocryptPackageNames;
}
public String uidSearchString() {
if (cachedUidSearchString == null) {
cachedUidSearchString = user_id_list();
if (cachedUidSearchString == null) {
cachedUidSearchString = "";
}
cachedUidSearchString = cachedUidSearchString.toLowerCase();
}
return cachedUidSearchString;
}
}

View File

@@ -0,0 +1,49 @@
package org.sufficientlysecure.keychain.model;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.auto.value.AutoValue;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
@AutoValue
public abstract class UserId {
public static UserId create(long master_key_id, int rank, String user_id,
String name, String email, String comment, boolean is_primary, boolean is_revoked, Long verified_int) {
return new AutoValue_UserId(master_key_id, rank, user_id, name, email, comment,
is_primary, is_revoked, verified_int
);
}
public abstract long master_key_id();
public abstract int rank();
@Nullable
public abstract String user_id();
@Nullable
public abstract String name();
@Nullable
public abstract String email();
@Nullable
public abstract String comment();
public abstract boolean is_primary();
public abstract boolean is_revoked();
public abstract Long verified_int();
public boolean isVerified() {
return verified() == VerificationStatus.VERIFIED_SECRET;
}
@NonNull
public VerificationStatus verified() {
return CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode(verified_int());
}
}

View File

@@ -1,67 +0,0 @@
package org.sufficientlysecure.keychain.model;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.annotation.NonNull;
import com.google.auto.value.AutoValue;
import org.sufficientlysecure.keychain.UserPacketsModel;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
@AutoValue
public abstract class UserPacket implements UserPacketsModel {
public static final Factory<UserPacket> FACTORY = new Factory<>(AutoValue_UserPacket::new);
public static final SelectUserIdsByMasterKeyIdMapper<UserId> USER_ID_MAPPER =
FACTORY.selectUserIdsByMasterKeyIdMapper(AutoValue_UserPacket_UserId::new);
public static final SelectUserAttributesByTypeAndMasterKeyIdMapper<UserAttribute> USER_ATTRIBUTE_MAPPER =
FACTORY.selectUserAttributesByTypeAndMasterKeyIdMapper(AutoValue_UserPacket_UserAttribute::new);
public static final UidStatusMapper<UidStatus> UID_STATUS_MAPPER =
FACTORY.selectUserIdStatusByEmailMapper(AutoValue_UserPacket_UidStatus::new);
public static UserPacket create(long masterKeyId, int rank, Long type, String userId, String name, String email,
String comment, byte[] attribute_data, boolean isPrimary, boolean isRevoked) {
return new AutoValue_UserPacket(masterKeyId, rank, type,
userId, name, email, comment, attribute_data, isPrimary, isRevoked);
}
public static InsertUserPacket createInsertStatement(SupportSQLiteDatabase db) {
return new InsertUserPacket(db);
}
public void bindTo(InsertUserPacket statement) {
statement.bind(master_key_id(), rank(), type(), user_id(), name(), email(), comment(), attribute_data(),
is_primary(), is_revoked());
}
@AutoValue
public static abstract class UserId implements SelectUserIdsByMasterKeyIdModel {
public boolean isVerified() {
return verified() == VerificationStatus.VERIFIED_SECRET;
}
@NonNull
public VerificationStatus verified() {
return CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode(verified_int());
}
}
@AutoValue
public static abstract class UserAttribute implements SelectUserAttributesByTypeAndMasterKeyIdModel {
public boolean isVerified() {
return verified() == VerificationStatus.VERIFIED_SECRET;
}
@NonNull
public VerificationStatus verified() {
return CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode(verified_int());
}
}
@AutoValue
public static abstract class UidStatus implements UidStatusModel {
public VerificationStatus keyStatus() {
return CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode(key_status_int());
}
}
}

View File

@@ -40,7 +40,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.ExportResult; import org.sufficientlysecure.keychain.operations.results.ExportResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;

View File

@@ -21,7 +21,7 @@ package org.sufficientlysecure.keychain.operations;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.RevokeResult; import org.sufficientlysecure.keychain.operations.results.RevokeResult;

View File

@@ -26,8 +26,8 @@ import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.OpenPgpSignatureResult.SenderStatusResult; import org.openintents.openpgp.OpenPgpSignatureResult.SenderStatusResult;
import org.openintents.openpgp.util.OpenPgpUtils; import org.openintents.openpgp.util.OpenPgpUtils;
import org.openintents.openpgp.util.OpenPgpUtils.UserId; import org.openintents.openpgp.util.OpenPgpUtils.UserId;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import timber.log.Timber; import timber.log.Timber;

View File

@@ -8,20 +8,20 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import android.content.Context; import android.content.Context;
import androidx.annotation.Nullable;
import android.text.format.DateUtils; import android.text.format.DateUtils;
import androidx.annotation.Nullable;
import org.openintents.openpgp.AutocryptPeerUpdate; import org.openintents.openpgp.AutocryptPeerUpdate;
import org.openintents.openpgp.AutocryptPeerUpdate.PreferEncrypt; import org.openintents.openpgp.AutocryptPeerUpdate.PreferEncrypt;
import org.sufficientlysecure.keychain.Autocrypt_peers;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.model.AutocryptPeer; import org.sufficientlysecure.keychain.SelectAutocryptKeyStatus;
import org.sufficientlysecure.keychain.model.AutocryptPeer.AutocryptKeyStatus; import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin; import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.model.GossipOrigin;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import timber.log.Timber; import timber.log.Timber;
@@ -48,17 +48,17 @@ public class AutocryptInteractor {
} }
void updateAutocryptPeerState(String autocryptPeerId, AutocryptPeerUpdate autocryptPeerUpdate) { void updateAutocryptPeerState(String autocryptPeerId, AutocryptPeerUpdate autocryptPeerUpdate) {
AutocryptPeer currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId); Autocrypt_peers currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId);
Date effectiveDate = autocryptPeerUpdate.getEffectiveDate(); Date effectiveDate = autocryptPeerUpdate.getEffectiveDate();
// 1. If the messages effective date is older than the peers[from-addr].autocrypt_timestamp value, then no changes are required, and the update process terminates. // 1. If the messages effective date is older than the peers[from-addr].autocrypt_timestamp value, then no changes are required, and the update process terminates.
Date lastSeenKey = currentAutocryptPeer != null ? currentAutocryptPeer.last_seen_key() : null; Date lastSeenKey = currentAutocryptPeer != null ? currentAutocryptPeer.getLast_seen_key() : null;
if (lastSeenKey != null && effectiveDate.compareTo(lastSeenKey) <= 0) { if (lastSeenKey != null && effectiveDate.compareTo(lastSeenKey) <= 0) {
return; return;
} }
// 2. If the messages effective date is more recent than peers[from-addr].last_seen then set peers[from-addr].last_seen to the messages effective date. // 2. If the messages effective date is more recent than peers[from-addr].last_seen then set peers[from-addr].last_seen to the messages effective date.
Date lastSeen = currentAutocryptPeer != null ? currentAutocryptPeer.last_seen() : null; Date lastSeen = currentAutocryptPeer != null ? currentAutocryptPeer.getLast_seen() : null;
if (lastSeen == null || effectiveDate.after(lastSeen)) { if (lastSeen == null || effectiveDate.after(lastSeen)) {
autocryptPeerDao.insertOrUpdateLastSeen(packageName, autocryptPeerId, effectiveDate); autocryptPeerDao.insertOrUpdateLastSeen(packageName, autocryptPeerId, effectiveDate);
} }
@@ -83,14 +83,14 @@ public class AutocryptInteractor {
} }
void updateAutocryptPeerGossipState(String autocryptPeerId, AutocryptPeerUpdate autocryptPeerUpdate) { void updateAutocryptPeerGossipState(String autocryptPeerId, AutocryptPeerUpdate autocryptPeerUpdate) {
AutocryptPeer currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId); Autocrypt_peers currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId);
Date effectiveDate = autocryptPeerUpdate.getEffectiveDate(); Date effectiveDate = autocryptPeerUpdate.getEffectiveDate();
// 1. If gossip-addr does not match any recipient in the mails To or Cc header, the update process terminates (i.e., header is ignored). // 1. If gossip-addr does not match any recipient in the mails To or Cc header, the update process terminates (i.e., header is ignored).
// -> This should be taken care of in the mail client that sends us this data! // -> This should be taken care of in the mail client that sends us this data!
// 2. If peers[gossip-addr].gossip_timestamp is more recent than the messages effective date, then the update process terminates. // 2. If peers[gossip-addr].gossip_timestamp is more recent than the messages effective date, then the update process terminates.
Date lastSeenGossip = currentAutocryptPeer != null ? currentAutocryptPeer.gossip_last_seen_key() : null; Date lastSeenGossip = currentAutocryptPeer != null ? currentAutocryptPeer.getGossip_last_seen_key() : null;
if (lastSeenGossip != null && lastSeenGossip.after(effectiveDate)) { if (lastSeenGossip != null && lastSeenGossip.after(effectiveDate)) {
return; return;
} }
@@ -150,7 +150,7 @@ public class AutocryptInteractor {
public Map<String,AutocryptRecommendationResult> determineAutocryptRecommendations(String... autocryptIds) { public Map<String,AutocryptRecommendationResult> determineAutocryptRecommendations(String... autocryptIds) {
Map<String,AutocryptRecommendationResult> result = new HashMap<>(autocryptIds.length); Map<String,AutocryptRecommendationResult> result = new HashMap<>(autocryptIds.length);
for (AutocryptKeyStatus autocryptKeyStatus : autocryptPeerDao.getAutocryptKeyStatus(packageName, autocryptIds)) { for (SelectAutocryptKeyStatus autocryptKeyStatus : autocryptPeerDao.getAutocryptKeyStatus(packageName, autocryptIds)) {
AutocryptRecommendationResult peerResult = determineAutocryptRecommendation(autocryptKeyStatus); AutocryptRecommendationResult peerResult = determineAutocryptRecommendation(autocryptKeyStatus);
result.put(peerResult.peerId, peerResult); result.put(peerResult.peerId, peerResult);
} }
@@ -161,58 +161,60 @@ public class AutocryptInteractor {
/** Determines Autocrypt "ui-recommendation", according to spec. /** Determines Autocrypt "ui-recommendation", according to spec.
* See https://autocrypt.org/level1.html#recommendations-for-single-recipient-messages * See https://autocrypt.org/level1.html#recommendations-for-single-recipient-messages
*/ */
private AutocryptRecommendationResult determineAutocryptRecommendation(AutocryptKeyStatus autocryptKeyStatus) { private AutocryptRecommendationResult determineAutocryptRecommendation(
SelectAutocryptKeyStatus autocryptKeyStatus) {
AutocryptRecommendationResult keyRecommendation = determineAutocryptKeyRecommendation(autocryptKeyStatus); AutocryptRecommendationResult keyRecommendation = determineAutocryptKeyRecommendation(autocryptKeyStatus);
if (keyRecommendation != null) return keyRecommendation; if (keyRecommendation != null) return keyRecommendation;
AutocryptRecommendationResult gossipRecommendation = determineAutocryptGossipRecommendation(autocryptKeyStatus); AutocryptRecommendationResult gossipRecommendation = determineAutocryptGossipRecommendation(autocryptKeyStatus);
if (gossipRecommendation != null) return gossipRecommendation; if (gossipRecommendation != null) return gossipRecommendation;
return new AutocryptRecommendationResult(autocryptKeyStatus.autocryptPeer().identifier(), AutocryptState.DISABLE, null, false); return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.DISABLE, null, false);
} }
@Nullable @Nullable
private AutocryptRecommendationResult determineAutocryptKeyRecommendation(AutocryptKeyStatus autocryptKeyStatus) { private AutocryptRecommendationResult determineAutocryptKeyRecommendation(
AutocryptPeer autocryptPeer = autocryptKeyStatus.autocryptPeer(); SelectAutocryptKeyStatus autocryptKeyStatus) {
Long masterKeyId = autocryptKeyStatus.getMaster_key_id();
Long masterKeyId = autocryptPeer.master_key_id();
boolean hasKey = masterKeyId != null; boolean hasKey = masterKeyId != null;
boolean isRevoked = autocryptKeyStatus.isKeyRevoked(); boolean isRevoked = Boolean.TRUE.equals(autocryptKeyStatus.getKey_is_revoked());
boolean isExpired = autocryptKeyStatus.isKeyExpired(); boolean isExpired = autocryptKeyStatus.getKey_is_expired_int() != 0;
if (!hasKey || isRevoked || isExpired) { if (!hasKey || isRevoked || isExpired) {
return null; return null;
} }
Date lastSeen = autocryptPeer.last_seen(); Date lastSeen = autocryptKeyStatus.getLast_seen();
Date lastSeenKey = autocryptPeer.last_seen_key(); Date lastSeenKey = autocryptKeyStatus.getLast_seen_key();
boolean isVerified = autocryptKeyStatus.isKeyVerified(); boolean isVerified = autocryptKeyStatus.getKey_is_verified();
boolean isLastSeenOlderThanDiscourageTimespan = lastSeen != null && lastSeenKey != null && boolean isLastSeenOlderThanDiscourageTimespan = lastSeen != null && lastSeenKey != null &&
lastSeenKey.getTime() < (lastSeen.getTime() - AUTOCRYPT_DISCOURAGE_THRESHOLD_MILLIS); lastSeenKey.getTime() < (lastSeen.getTime() - AUTOCRYPT_DISCOURAGE_THRESHOLD_MILLIS);
if (isLastSeenOlderThanDiscourageTimespan) { if (isLastSeenOlderThanDiscourageTimespan) {
return new AutocryptRecommendationResult(autocryptPeer.identifier(), AutocryptState.DISCOURAGED_OLD, masterKeyId, isVerified); return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.DISCOURAGED_OLD, masterKeyId, isVerified);
} }
boolean isMutual = autocryptPeer.is_mutual(); boolean isMutual = autocryptKeyStatus.is_mutual();
if (isMutual) { if (isMutual) {
return new AutocryptRecommendationResult(autocryptPeer.identifier(), AutocryptState.MUTUAL, masterKeyId, isVerified); return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.MUTUAL, masterKeyId, isVerified);
} else { } else {
return new AutocryptRecommendationResult(autocryptPeer.identifier(), AutocryptState.AVAILABLE, masterKeyId, isVerified); return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.AVAILABLE, masterKeyId, isVerified);
} }
} }
@Nullable @Nullable
private AutocryptRecommendationResult determineAutocryptGossipRecommendation(AutocryptKeyStatus autocryptKeyStatus) { private AutocryptRecommendationResult determineAutocryptGossipRecommendation(
boolean gossipHasKey = autocryptKeyStatus.hasGossipKey(); SelectAutocryptKeyStatus autocryptKeyStatus) {
boolean gossipIsRevoked = autocryptKeyStatus.isGossipKeyRevoked(); boolean gossipHasKey = autocryptKeyStatus.getGossip_master_key_id() != null;
boolean gossipIsExpired = autocryptKeyStatus.isGossipKeyExpired(); boolean gossipIsRevoked =
boolean isVerified = autocryptKeyStatus.isGossipKeyVerified(); Boolean.TRUE.equals(autocryptKeyStatus.getGossip_key_is_revoked());
boolean gossipIsExpired = autocryptKeyStatus.getGossip_key_is_expired_int() != 0;
boolean isVerified = autocryptKeyStatus.getGossip_key_is_verified();
if (!gossipHasKey || gossipIsRevoked || gossipIsExpired) { if (!gossipHasKey || gossipIsRevoked || gossipIsExpired) {
return null; return null;
} }
Long masterKeyId = autocryptKeyStatus.autocryptPeer().gossip_master_key_id(); Long masterKeyId = autocryptKeyStatus.getGossip_master_key_id();
return new AutocryptRecommendationResult(autocryptKeyStatus.autocryptPeer().identifier(), AutocryptState.DISCOURAGED_GOSSIP, masterKeyId, isVerified); return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.DISCOURAGED_GOSSIP, masterKeyId, isVerified);
} }
public void updateKeyGossipFromSignature(String autocryptId, Date effectiveDate, long masterKeyId) { public void updateKeyGossipFromSignature(String autocryptId, Date effectiveDate, long masterKeyId) {

View File

@@ -31,14 +31,15 @@ import android.content.UriMatcher;
import android.database.Cursor; import android.database.Cursor;
import android.database.MatrixCursor; import android.database.MatrixCursor;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.NonNull;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull;
import org.sufficientlysecure.keychain.BuildConfig; import org.sufficientlysecure.keychain.BuildConfig;
import org.sufficientlysecure.keychain.UidStatus;
import org.sufficientlysecure.keychain.daos.ApiAppDao; import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager; import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
import org.sufficientlysecure.keychain.daos.UserIdDao; import org.sufficientlysecure.keychain.daos.UserIdDao;
import org.sufficientlysecure.keychain.model.UserPacket.UidStatus; import org.sufficientlysecure.keychain.model.CustomColumnAdapters;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract; import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptStatus; import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptStatus;
@@ -65,7 +66,8 @@ public class KeychainExternalProvider extends ContentProvider {
matcher.addURI(authority, KeychainExternalContract.BASE_EMAIL_STATUS, EMAIL_STATUS); matcher.addURI(authority, KeychainExternalContract.BASE_EMAIL_STATUS, EMAIL_STATUS);
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS, AUTOCRYPT_STATUS); matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS, AUTOCRYPT_STATUS);
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS + "/*", AUTOCRYPT_STATUS_INTERNAL); matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS + "/*",
AUTOCRYPT_STATUS_INTERNAL);
return matcher; return matcher;
} }
@@ -84,8 +86,9 @@ public class KeychainExternalProvider extends ContentProvider {
} }
@Override @Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, public Cursor query(@NonNull Uri uri, String[] projection, String selection,
String sortOrder) { String[] selectionArgs,
String sortOrder) {
Timber.v("query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")"); Timber.v("query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")");
Context context = getContext(); Context context = getContext();
if (context == null) { if (context == null) {
@@ -97,7 +100,8 @@ public class KeychainExternalProvider extends ContentProvider {
int match = uriMatcher.match(uri); int match = uriMatcher.match(uri);
switch (match) { switch (match) {
case EMAIL_STATUS: { case EMAIL_STATUS: {
Toast.makeText(context, "This API is no longer supported by OpenKeychain!", Toast.LENGTH_SHORT).show(); Toast.makeText(context, "This API is no longer supported by OpenKeychain!",
Toast.LENGTH_SHORT).show();
return new MatrixCursor(projection); return new MatrixCursor(projection);
} }
@@ -107,12 +111,14 @@ public class KeychainExternalProvider extends ContentProvider {
} }
// override package name to use any external // override package name to use any external
callingPackageName = uri.getLastPathSegment(); callingPackageName = uri.getLastPathSegment();
case AUTOCRYPT_STATUS: { case AUTOCRYPT_STATUS: {
boolean callerIsAllowed = (match == AUTOCRYPT_STATUS_INTERNAL) || apiPermissionHelper.isAllowedIgnoreErrors(); boolean callerIsAllowed = (match == AUTOCRYPT_STATUS_INTERNAL) ||
apiPermissionHelper.isAllowedIgnoreErrors();
if (!callerIsAllowed) { if (!callerIsAllowed) {
throw new AccessControlException("An application must register before use of KeychainExternalProvider!"); throw new AccessControlException(
"An application must register before use of KeychainExternalProvider!");
} }
if (projection == null) { if (projection == null) {
@@ -120,25 +126,32 @@ public class KeychainExternalProvider extends ContentProvider {
} }
List<String> plist = Arrays.asList(projection); List<String> plist = Arrays.asList(projection);
boolean isWildcardSelector = selectionArgs.length == 1 && selectionArgs[0].contains("%"); boolean isWildcardSelector =
selectionArgs.length == 1 && selectionArgs[0].contains("%");
boolean queriesUidResult = plist.contains(AutocryptStatus.UID_KEY_STATUS) || boolean queriesUidResult = plist.contains(AutocryptStatus.UID_KEY_STATUS) ||
plist.contains(AutocryptStatus.UID_ADDRESS) || plist.contains(AutocryptStatus.UID_ADDRESS) ||
plist.contains(AutocryptStatus.UID_MASTER_KEY_ID) || plist.contains(AutocryptStatus.UID_MASTER_KEY_ID) ||
plist.contains(AutocryptStatus.UID_CANDIDATES); plist.contains(AutocryptStatus.UID_CANDIDATES);
boolean queriesAutocryptResult = plist.contains(AutocryptStatus.AUTOCRYPT_PEER_STATE) || boolean queriesAutocryptResult =
plist.contains(AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID) || plist.contains(AutocryptStatus.AUTOCRYPT_PEER_STATE) ||
plist.contains(AutocryptStatus.AUTOCRYPT_KEY_STATUS); plist.contains(AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID) ||
plist.contains(AutocryptStatus.AUTOCRYPT_KEY_STATUS);
if (isWildcardSelector && queriesAutocryptResult) { if (isWildcardSelector && queriesAutocryptResult) {
throw new UnsupportedOperationException("Cannot wildcard-query autocrypt results!"); throw new UnsupportedOperationException(
"Cannot wildcard-query autocrypt results!");
} }
Map<String, UidStatus> uidStatuses = queriesUidResult ? Map<String, UidStatus> uidStatuses = queriesUidResult ?
loadUidStatusMap(selectionArgs, isWildcardSelector) : Collections.emptyMap(); loadUidStatusMap(selectionArgs, isWildcardSelector) :
Map<String, AutocryptRecommendationResult> autocryptStates = queriesAutocryptResult ? Collections.emptyMap();
loadAutocryptRecommendationMap(selectionArgs, callingPackageName) : Collections.emptyMap(); Map<String, AutocryptRecommendationResult> autocryptStates =
queriesAutocryptResult ?
loadAutocryptRecommendationMap(selectionArgs, callingPackageName) :
Collections.emptyMap();
MatrixCursor cursor = MatrixCursor cursor =
mapResultsToProjectedMatrixCursor(projection, selectionArgs, uidStatuses, autocryptStates); mapResultsToProjectedMatrixCursor(projection, selectionArgs, uidStatuses,
autocryptStates);
uri = DatabaseNotifyManager.getNotifyUriAllKeys(); uri = DatabaseNotifyManager.getNotifyUriAllKeys();
cursor.setNotificationUri(context.getContentResolver(), uri); cursor.setNotificationUri(context.getContentResolver(), uri);
@@ -153,8 +166,10 @@ public class KeychainExternalProvider extends ContentProvider {
} }
@NonNull @NonNull
private MatrixCursor mapResultsToProjectedMatrixCursor(String[] projection, String[] selectionArgs, private MatrixCursor mapResultsToProjectedMatrixCursor(String[] projection,
Map<String, UidStatus> uidStatuses, Map<String, AutocryptRecommendationResult> autocryptStates) { String[] selectionArgs,
Map<String, UidStatus> uidStatuses,
Map<String, AutocryptRecommendationResult> autocryptStates) {
MatrixCursor cursor = new MatrixCursor(projection); MatrixCursor cursor = new MatrixCursor(projection);
for (String selectionArg : selectionArgs) { for (String selectionArg : selectionArgs) {
AutocryptRecommendationResult autocryptResult = autocryptStates.get(selectionArg); AutocryptRecommendationResult autocryptResult = autocryptStates.get(selectionArg);
@@ -162,7 +177,8 @@ public class KeychainExternalProvider extends ContentProvider {
Object[] row = new Object[projection.length]; Object[] row = new Object[projection.length];
for (int i = 0; i < projection.length; i++) { for (int i = 0; i < projection.length; i++) {
if (AutocryptStatus.ADDRESS.equals(projection[i]) || AutocryptStatus._ID.equals(projection[i])) { if (AutocryptStatus.ADDRESS.equals(projection[i]) ||
AutocryptStatus._ID.equals(projection[i])) {
row[i] = selectionArg; row[i] = selectionArg;
} else { } else {
row[i] = columnNameToRowContent(projection[i], autocryptResult, uidStatus); row[i] = columnNameToRowContent(projection[i], autocryptResult, uidStatus);
@@ -180,7 +196,8 @@ public class KeychainExternalProvider extends ContentProvider {
if (uidStatus == null) { if (uidStatus == null) {
return null; return null;
} }
return uidStatus.keyStatus() == VerificationStatus.VERIFIED_SECRET ? return CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode(
uidStatus.getKey_status_int()) == VerificationStatus.VERIFIED_SECRET ?
KeychainExternalContract.KEY_STATUS_VERIFIED : KeychainExternalContract.KEY_STATUS_VERIFIED :
KeychainExternalContract.KEY_STATUS_UNVERIFIED; KeychainExternalContract.KEY_STATUS_UNVERIFIED;
} }
@@ -188,19 +205,19 @@ public class KeychainExternalProvider extends ContentProvider {
if (uidStatus == null) { if (uidStatus == null) {
return null; return null;
} }
return uidStatus.user_id(); return uidStatus.getUser_id();
case AutocryptStatus.UID_MASTER_KEY_ID: case AutocryptStatus.UID_MASTER_KEY_ID:
if (uidStatus == null) { if (uidStatus == null) {
return null; return null;
} }
return uidStatus.master_key_id(); return uidStatus.getMaster_key_id();
case AutocryptStatus.UID_CANDIDATES: case AutocryptStatus.UID_CANDIDATES:
if (uidStatus == null) { if (uidStatus == null) {
return null; return null;
} }
return uidStatus.candidates(); return uidStatus.getCandidates();
case AutocryptStatus.AUTOCRYPT_PEER_STATE: case AutocryptStatus.AUTOCRYPT_PEER_STATE:
if (autocryptResult == null) { if (autocryptResult == null) {
@@ -213,7 +230,8 @@ public class KeychainExternalProvider extends ContentProvider {
return null; return null;
} }
return autocryptResult.isVerified ? return autocryptResult.isVerified ?
KeychainExternalContract.KEY_STATUS_VERIFIED : KeychainExternalContract.KEY_STATUS_UNVERIFIED; KeychainExternalContract.KEY_STATUS_VERIFIED :
KeychainExternalContract.KEY_STATUS_UNVERIFIED;
case AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID: case AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID:
if (autocryptResult == null) { if (autocryptResult == null) {
@@ -226,10 +244,12 @@ public class KeychainExternalProvider extends ContentProvider {
} }
} }
private Map<String, UidStatus> loadUidStatusMap(String[] selectionArgs, boolean isWildcardSelector) { private Map<String, org.sufficientlysecure.keychain.UidStatus> loadUidStatusMap(
String[] selectionArgs, boolean isWildcardSelector) {
UserIdDao userIdDao = UserIdDao.getInstance(getContext()); UserIdDao userIdDao = UserIdDao.getInstance(getContext());
if (isWildcardSelector) { if (isWildcardSelector) {
UidStatus uidStatus = userIdDao.getUidStatusByEmailLike(selectionArgs[0]); org.sufficientlysecure.keychain.UidStatus uidStatus =
userIdDao.getUidStatusByEmailLike(selectionArgs[0]);
return Collections.singletonMap(selectionArgs[0], uidStatus); return Collections.singletonMap(selectionArgs[0], uidStatus);
} else { } else {
return userIdDao.getUidStatusByEmail(selectionArgs); return userIdDao.getUidStatusByEmail(selectionArgs);
@@ -238,17 +258,23 @@ public class KeychainExternalProvider extends ContentProvider {
private Map<String, AutocryptRecommendationResult> loadAutocryptRecommendationMap( private Map<String, AutocryptRecommendationResult> loadAutocryptRecommendationMap(
String[] selectionArgs, String callingPackageName) { String[] selectionArgs, String callingPackageName) {
AutocryptInteractor autocryptInteractor = AutocryptInteractor.getInstance(getContext(), callingPackageName); AutocryptInteractor autocryptInteractor =
AutocryptInteractor.getInstance(getContext(), callingPackageName);
return autocryptInteractor.determineAutocryptRecommendations(selectionArgs); return autocryptInteractor.determineAutocryptRecommendations(selectionArgs);
} }
private int getPeerStateValue(AutocryptState autocryptState) { private int getPeerStateValue(AutocryptState autocryptState) {
switch (autocryptState) { switch (autocryptState) {
case DISABLE: return AutocryptStatus.AUTOCRYPT_PEER_DISABLED; case DISABLE:
case DISCOURAGED_OLD: return AutocryptStatus.AUTOCRYPT_PEER_DISCOURAGED_OLD; return AutocryptStatus.AUTOCRYPT_PEER_DISABLED;
case DISCOURAGED_GOSSIP: return AutocryptStatus.AUTOCRYPT_PEER_GOSSIP; case DISCOURAGED_OLD:
case AVAILABLE: return AutocryptStatus.AUTOCRYPT_PEER_AVAILABLE; return AutocryptStatus.AUTOCRYPT_PEER_DISCOURAGED_OLD;
case MUTUAL: return AutocryptStatus.AUTOCRYPT_PEER_MUTUAL; case DISCOURAGED_GOSSIP:
return AutocryptStatus.AUTOCRYPT_PEER_GOSSIP;
case AVAILABLE:
return AutocryptStatus.AUTOCRYPT_PEER_AVAILABLE;
case MUTUAL:
return AutocryptStatus.AUTOCRYPT_PEER_MUTUAL;
} }
throw new IllegalStateException("Unhandled case!"); throw new IllegalStateException("Unhandled case!");
} }
@@ -269,7 +295,8 @@ public class KeychainExternalProvider extends ContentProvider {
} }
@Override @Override
public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) { public int update(@NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@@ -57,7 +57,7 @@ import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.daos.OverriddenWarningsDao; import org.sufficientlysecure.keychain.daos.OverriddenWarningsDao;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.BackupOperation; import org.sufficientlysecure.keychain.operations.BackupOperation;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.ExportResult; import org.sufficientlysecure.keychain.operations.results.ExportResult;

View File

@@ -43,7 +43,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.daos.ApiAppDao; import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.SshPublicKey; import org.sufficientlysecure.keychain.pgp.SshPublicKey;

View File

@@ -27,17 +27,17 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import androidx.fragment.app.FragmentManager;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.fragment.app.FragmentManager;
import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Api_apps;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.ApiApp;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.daos.ApiAppDao; import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.ui.dialog.AdvancedAppSettingsDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.AdvancedAppSettingsDialogFragment;
import timber.log.Timber; import timber.log.Timber;
@@ -53,7 +53,7 @@ public class AppSettingsActivity extends BaseActivity {
// model // model
ApiApp mApiApp; Api_apps mApiApp;
private ApiAppDao apiAppDao; private ApiAppDao apiAppDao;
@Override @Override
@@ -140,7 +140,7 @@ public class AppSettingsActivity extends BaseActivity {
// advanced info: package certificate SHA-256 // advanced info: package certificate SHA-256
try { try {
MessageDigest md = MessageDigest.getInstance("SHA-256"); MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(mApiApp.package_signature()); md.update(mApiApp.getPackage_signature());
byte[] digest = md.digest(); byte[] digest = md.digest();
certificate = new String(Hex.encode(digest)); certificate = new String(Hex.encode(digest));
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
@@ -148,7 +148,7 @@ public class AppSettingsActivity extends BaseActivity {
} }
AdvancedAppSettingsDialogFragment dialogFragment = AdvancedAppSettingsDialogFragment dialogFragment =
AdvancedAppSettingsDialogFragment.newInstance(mApiApp.package_name(), certificate); AdvancedAppSettingsDialogFragment.newInstance(mApiApp.getPackage_name(), certificate);
dialogFragment.show(getSupportFragmentManager(), "advancedDialog"); dialogFragment.show(getSupportFragmentManager(), "advancedDialog");
} }
@@ -157,7 +157,7 @@ public class AppSettingsActivity extends BaseActivity {
Intent i; Intent i;
PackageManager manager = getPackageManager(); PackageManager manager = getPackageManager();
try { try {
i = manager.getLaunchIntentForPackage(mApiApp.package_name()); i = manager.getLaunchIntentForPackage(mApiApp.getPackage_name());
if (i == null) if (i == null)
throw new PackageManager.NameNotFoundException(); throw new PackageManager.NameNotFoundException();
// start like the Android launcher would do // start like the Android launcher would do
@@ -177,13 +177,13 @@ public class AppSettingsActivity extends BaseActivity {
Drawable appIcon = null; Drawable appIcon = null;
PackageManager pm = getApplicationContext().getPackageManager(); PackageManager pm = getApplicationContext().getPackageManager();
try { try {
ApplicationInfo ai = pm.getApplicationInfo(mApiApp.package_name(), 0); ApplicationInfo ai = pm.getApplicationInfo(mApiApp.getPackage_name(), 0);
appName = (String) pm.getApplicationLabel(ai); appName = (String) pm.getApplicationLabel(ai);
appIcon = pm.getApplicationIcon(ai); appIcon = pm.getApplicationIcon(ai);
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
// fallback // fallback
appName = mApiApp.package_name(); appName = mApiApp.getPackage_name();
} }
mAppNameView.setText(appName); mAppNameView.setText(appName);
mAppIconView.setImageDrawable(appIcon); mAppIconView.setImageDrawable(appIcon);

View File

@@ -27,7 +27,7 @@ import android.os.Bundle;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.daos.ApiAppDao; import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter; import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;

View File

@@ -25,8 +25,8 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import org.sufficientlysecure.keychain.Api_apps;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.ApiApp;
import org.sufficientlysecure.keychain.daos.ApiAppDao; import org.sufficientlysecure.keychain.daos.ApiAppDao;
import timber.log.Timber; import timber.log.Timber;
@@ -39,7 +39,7 @@ class RemoteRegisterPresenter {
private RemoteRegisterView view; private RemoteRegisterView view;
private Intent resultData; private Intent resultData;
private ApiApp apiApp; private Api_apps apiApp;
RemoteRegisterPresenter(Context context) { RemoteRegisterPresenter(Context context) {
@@ -54,7 +54,7 @@ class RemoteRegisterPresenter {
} }
void setupFromIntentData(Intent resultData, String packageName, byte[] packageSignature) { void setupFromIntentData(Intent resultData, String packageName, byte[] packageSignature) {
this.apiApp = ApiApp.create(packageName, packageSignature); this.apiApp = new Api_apps(0L, packageName, packageSignature);
this.resultData = resultData; this.resultData = resultData;
try { try {

View File

@@ -26,7 +26,7 @@ import android.graphics.drawable.Drawable;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.daos.ApiAppDao; import org.sufficientlysecure.keychain.daos.ApiAppDao;

View File

@@ -31,7 +31,7 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter; import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;
import org.sufficientlysecure.keychain.ui.base.RecyclerFragment; import org.sufficientlysecure.keychain.ui.base.RecyclerFragment;

View File

@@ -21,24 +21,23 @@ package org.sufficientlysecure.keychain.remote.ui;
import java.util.List; import java.util.List;
import android.app.Activity; import android.app.Activity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProviders;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpUtils; import org.openintents.openpgp.util.OpenPgpUtils;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.ApiApp;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.daos.ApiAppDao; import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity; import org.sufficientlysecure.keychain.ui.CreateKeyActivity;
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter; import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;
import org.sufficientlysecure.keychain.ui.base.RecyclerFragment; import org.sufficientlysecure.keychain.ui.base.RecyclerFragment;
@@ -117,7 +116,7 @@ public class SelectSignKeyIdListFragment extends RecyclerFragment<KeyChoiceAdapt
GenericViewModel viewModel = ViewModelProviders.of(this).get(GenericViewModel.class); GenericViewModel viewModel = ViewModelProviders.of(this).get(GenericViewModel.class);
LiveData<List<UnifiedKeyInfo>> liveData = viewModel.getGenericLiveData( LiveData<List<UnifiedKeyInfo>> liveData = viewModel.getGenericLiveData(
requireContext(), keyRepository::getAllUnifiedKeyInfoWithSecret); requireContext(), keyRepository::getAllUnifiedKeyInfoWithSecret);
liveData.observe(this, this::onLoadUnifiedKeyData); liveData.observe(getViewLifecycleOwner(), this::onLoadUnifiedKeyData);
} }
public void onLoadUnifiedKeyData(List<UnifiedKeyInfo> data) { public void onLoadUnifiedKeyData(List<UnifiedKeyInfo> data) {
@@ -155,8 +154,7 @@ public class SelectSignKeyIdListFragment extends RecyclerFragment<KeyChoiceAdapt
} }
private void onSelectKeyItemClicked(UnifiedKeyInfo keyInfo) { private void onSelectKeyItemClicked(UnifiedKeyInfo keyInfo) {
ApiApp apiApp = ApiApp.create(packageName, packageSignature); apiAppDao.insertApiApp(packageName, packageSignature);
apiAppDao.insertApiApp(apiApp);
apiAppDao.addAllowedKeyIdForApp(packageName, keyInfo.master_key_id()); apiAppDao.addAllowedKeyIdForApp(packageName, keyInfo.master_key_id());
resultIntent.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, keyInfo.master_key_id()); resultIntent.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, keyInfo.master_key_id());

View File

@@ -15,7 +15,7 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.remote.ui.dialog.DialogKeyChoiceAdapter.KeyChoiceViewHolder; import org.sufficientlysecure.keychain.remote.ui.dialog.DialogKeyChoiceAdapter.KeyChoiceViewHolder;
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter; import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;

View File

@@ -46,7 +46,7 @@ import android.widget.Toast;
import com.mikepenz.materialdrawer.util.KeyboardUtil; import com.mikepenz.materialdrawer.util.KeyboardUtil;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.livedata.GenericLiveData; import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity; import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity;
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicatePresenter.RemoteDeduplicateView; import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicatePresenter.RemoteDeduplicateView;

View File

@@ -25,7 +25,7 @@ import android.content.Context;
import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.Adapter;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.remote.AutocryptInteractor; import org.sufficientlysecure.keychain.remote.AutocryptInteractor;
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicateActivity.DeduplicateViewModel; import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicateActivity.DeduplicateViewModel;
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter; import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;

View File

@@ -23,9 +23,6 @@ import java.util.List;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProviders;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@@ -33,26 +30,29 @@ import android.content.res.Resources;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState; import android.graphics.drawable.Drawable.ConstantState;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.mikepenz.materialdrawer.util.KeyboardUtil; import com.mikepenz.materialdrawer.util.KeyboardUtil;
import org.openintents.ssh.authentication.SshAuthenticationApi; import org.openintents.ssh.authentication.SshAuthenticationApi;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.ApiAppDao; import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.livedata.GenericLiveData; import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity; import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity;
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyPresenter.RemoteSelectAuthenticationKeyView; import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyPresenter.RemoteSelectAuthenticationKeyView;
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;

View File

@@ -27,7 +27,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyActivity.SelectAuthKeyViewModel; import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyActivity.SelectAuthKeyViewModel;
import timber.log.Timber; import timber.log.Timber;

View File

@@ -61,7 +61,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.livedata.GenericLiveData; import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.livedata.PgpKeyGenerationLiveData; import org.sufficientlysecure.keychain.livedata.PgpKeyGenerationLiveData;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectIdentityKeyPresenter.RemoteSelectIdentityKeyView; import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectIdentityKeyPresenter.RemoteSelectIdentityKeyView;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.ImportKeyringParcel;

View File

@@ -33,9 +33,9 @@ import android.text.TextUtils;
import org.openintents.openpgp.util.OpenPgpUtils; import org.openintents.openpgp.util.OpenPgpUtils;
import org.openintents.openpgp.util.OpenPgpUtils.UserId; import org.openintents.openpgp.util.OpenPgpUtils.UserId;
import org.sufficientlysecure.keychain.Api_apps;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.model.ApiApp; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
@@ -59,7 +59,7 @@ class RemoteSelectIdentityKeyPresenter {
private Long selectedMasterKeyId; private Long selectedMasterKeyId;
private byte[] generatedKeyData; private byte[] generatedKeyData;
private ApiAppDao apiAppDao; private ApiAppDao apiAppDao;
private ApiApp apiApp; private Api_apps apiApp;
RemoteSelectIdentityKeyPresenter(Context context, LifecycleOwner lifecycleOwner) { RemoteSelectIdentityKeyPresenter(Context context, LifecycleOwner lifecycleOwner) {
@@ -98,7 +98,7 @@ class RemoteSelectIdentityKeyPresenter {
Drawable appIcon = packageManager.getApplicationIcon(applicationInfo); Drawable appIcon = packageManager.getApplicationIcon(applicationInfo);
CharSequence appLabel = packageManager.getApplicationLabel(applicationInfo); CharSequence appLabel = packageManager.getApplicationLabel(applicationInfo);
apiApp = ApiApp.create(packageName, packageSignature); apiApp = new Api_apps(0L, packageName, packageSignature);
view.setTitleClientIconAndName(appIcon, appLabel); view.setTitleClientIconAndName(appIcon, appLabel);
} }
@@ -217,14 +217,14 @@ class RemoteSelectIdentityKeyPresenter {
void onHighlightFinished() { void onHighlightFinished() {
apiAppDao.insertApiApp(apiApp); apiAppDao.insertApiApp(apiApp);
apiAppDao.addAllowedKeyIdForApp(apiApp.package_name(), Objects.requireNonNull(selectedMasterKeyId)); apiAppDao.addAllowedKeyIdForApp(apiApp.getPackage_name(), Objects.requireNonNull(selectedMasterKeyId));
view.finishAndReturn(selectedMasterKeyId); view.finishAndReturn(selectedMasterKeyId);
} }
void onImportOpSuccess(ImportKeyResult result) { void onImportOpSuccess(ImportKeyResult result) {
long importedMasterKeyId = result.getImportedMasterKeyIds()[0]; long importedMasterKeyId = result.getImportedMasterKeyIds()[0];
apiAppDao.insertApiApp(apiApp); apiAppDao.insertApiApp(apiApp);
apiAppDao.addAllowedKeyIdForApp(apiApp.package_name(), importedMasterKeyId); apiAppDao.addAllowedKeyIdForApp(apiApp.getPackage_name(), importedMasterKeyId);
view.finishAndReturn(importedMasterKeyId); view.finishAndReturn(importedMasterKeyId);
} }

View File

@@ -32,23 +32,23 @@ import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import android.util.Pair; import android.util.Pair;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.ExportResult; import org.sufficientlysecure.keychain.operations.results.ExportResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.provider.TemporaryFileProvider; import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.service.BackupKeyringParcel; import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@@ -131,8 +131,8 @@ public class BackupRestoreFragment extends CryptoOperationFragment<BackupKeyring
} }
private Long getFirstSubKeyWithPassphrase(long masterKeyId) { private Long getFirstSubKeyWithPassphrase(long masterKeyId) {
for (SubKey subKey : keyRepository.getSubKeysByMasterKeyId(masterKeyId)) { for (Keys subKey : keyRepository.getSubKeysByMasterKeyId(masterKeyId)) {
switch (subKey.has_secret()) { switch (subKey.getHas_secret()) {
case PASSPHRASE_EMPTY: case PASSPHRASE_EMPTY:
case DIVERT_TO_CARD: case DIVERT_TO_CARD:
case UNAVAILABLE: case UNAVAILABLE:
@@ -140,7 +140,7 @@ public class BackupRestoreFragment extends CryptoOperationFragment<BackupKeyring
case GNU_DUMMY: case GNU_DUMMY:
continue; continue;
default: { default: {
return subKey.key_id(); return subKey.getKey_id();
} }
} }
} }

View File

@@ -30,7 +30,7 @@ import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel; import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;

View File

@@ -37,7 +37,7 @@ import android.widget.ImageView;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;

View File

@@ -26,8 +26,6 @@ import java.util.regex.Pattern;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@@ -38,18 +36,20 @@ import android.widget.Button;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import org.bouncycastle.bcpg.sig.KeyFlags; import org.bouncycastle.bcpg.sig.KeyFlags;
import org.openintents.openpgp.util.OpenPgpUtils; import org.openintents.openpgp.util.OpenPgpUtils;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.model.SubKey;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.UploadResult; import org.sufficientlysecure.keychain.operations.results.UploadResult;
import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.service.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.ChangeUnlockParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
@@ -420,9 +420,9 @@ public class CreateKeyFinalFragment extends Fragment {
return; return;
} }
List<SubKey> subKeys = keyRepository.getSubKeysByMasterKeyId(saveKeyResult.mMasterKeyId); List<Keys> subKeys = keyRepository.getSubKeysByMasterKeyId(saveKeyResult.mMasterKeyId);
for (SubKey subKey : subKeys) { for (Keys subKey : subKeys) {
builder.addOrReplaceSubkeyChange(SubkeyChange.createMoveToSecurityTokenChange(subKey.key_id())); builder.addOrReplaceSubkeyChange(SubkeyChange.createMoveToSecurityTokenChange(subKey.getKey_id()));
} }
// define new PIN and Admin PIN for the card // define new PIN and Admin PIN for the card

View File

@@ -40,7 +40,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.livedata.GenericLiveData; import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;

View File

@@ -37,7 +37,7 @@ import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.DeleteResult; import org.sufficientlysecure.keychain.operations.results.DeleteResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.RevokeResult; import org.sufficientlysecure.keychain.operations.results.RevokeResult;

View File

@@ -39,7 +39,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.livedata.GenericLiveData; import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput; import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput;
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip; import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip;
import org.sufficientlysecure.keychain.ui.widget.KeySpinner; import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
@@ -121,8 +121,8 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
EncryptModeViewModel viewModel = ViewModelProviders.of(this).get(EncryptModeViewModel.class); EncryptModeViewModel viewModel = ViewModelProviders.of(this).get(EncryptModeViewModel.class);
viewModel.getSignKeyLiveData(requireContext()).observe(this, mSignKeySpinner::setData); viewModel.getSignKeyLiveData(requireContext()).observe(getViewLifecycleOwner(), mSignKeySpinner::setData);
viewModel.getEncryptRecipientLiveData(requireContext()).observe(this, mEncryptKeyView::setData); viewModel.getEncryptRecipientLiveData(requireContext()).observe(getViewLifecycleOwner(), mEncryptKeyView::setData);
// preselect keys given, from state or arguments // preselect keys given, from state or arguments
if (savedInstanceState == null) { if (savedInstanceState == null) {

View File

@@ -58,7 +58,7 @@ import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager; import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.keysync.KeyserverSyncManager; import org.sufficientlysecure.keychain.keysync.KeyserverSyncManager;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.KeySyncParcel; import org.sufficientlysecure.keychain.operations.KeySyncParcel;
import org.sufficientlysecure.keychain.operations.results.BenchmarkResult; import org.sufficientlysecure.keychain.operations.results.BenchmarkResult;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
@@ -252,7 +252,7 @@ public class KeyListFragment extends RecyclerFragment<FlexibleAdapter<FlexibleKe
GenericViewModel viewModel = ViewModelProviders.of(this).get(GenericViewModel.class); GenericViewModel viewModel = ViewModelProviders.of(this).get(GenericViewModel.class);
LiveData<List<FlexibleKeyItem>> liveData = viewModel.getGenericLiveData(requireContext(), this::loadFlexibleKeyItems); LiveData<List<FlexibleKeyItem>> liveData = viewModel.getGenericLiveData(requireContext(), this::loadFlexibleKeyItems);
liveData.observe(this, this::onLoadKeyItems); liveData.observe(getViewLifecycleOwner(), this::onLoadKeyItems);
} }
@WorkerThread @WorkerThread

View File

@@ -21,23 +21,23 @@ package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import androidx.lifecycle.LiveData;
import android.database.MatrixCursor; import android.database.MatrixCursor;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcel; import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ListView; import android.widget.ListView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LiveData;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.UserId;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter; import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter;
import timber.log.Timber; import timber.log.Timber;
@@ -85,7 +85,7 @@ public class MultiUserIdsFragment extends Fragment {
KeyRepository keyRepository = KeyRepository.create(activity); KeyRepository keyRepository = KeyRepository.create(activity);
LiveData<List<UserId>> userIdLiveData = LiveData<List<UserId>> userIdLiveData =
new GenericLiveData<>(getContext(), () -> keyRepository.getUserIds(pubMasterKeyIds)); new GenericLiveData<>(getContext(), () -> keyRepository.getUserIds(pubMasterKeyIds));
userIdLiveData.observe(this, this::onUserIdsLoaded); userIdLiveData.observe(getViewLifecycleOwner(), this::onUserIdsLoaded);
} }

View File

@@ -52,7 +52,7 @@ import android.widget.ViewAnimator;
import org.openintents.openpgp.util.OpenPgpUtils; import org.openintents.openpgp.util.OpenPgpUtils;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;

View File

@@ -28,7 +28,7 @@ import android.widget.ImageView;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel; import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;

View File

@@ -9,19 +9,19 @@ import java.util.TimeZone;
import android.content.Context; import android.content.Context;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.Typeface; import android.graphics.Typeface;
import androidx.annotation.StringRes;
import android.text.format.DateFormat; import android.text.format.DateFormat;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.StringRes;
import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFlexible; import eu.davidea.flexibleadapter.items.IFlexible;
import eu.davidea.viewholders.FlexibleViewHolder; import eu.davidea.viewholders.FlexibleViewHolder;
import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Builder; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Builder;
@@ -32,22 +32,22 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
public class SubKeyItem extends AbstractFlexibleItem<SubKeyItem.SubkeyViewHolder> { public class SubKeyItem extends AbstractFlexibleItem<SubKeyItem.SubkeyViewHolder> {
final SubKey subkeyInfo; final Keys subkeyInfo;
private final SubkeyEditViewModel viewModel; private final SubkeyEditViewModel viewModel;
SubKeyItem(SubKey subkeyInfo, SubkeyEditViewModel viewModel) { SubKeyItem(Keys subkeyInfo, SubkeyEditViewModel viewModel) {
this.subkeyInfo = subkeyInfo; this.subkeyInfo = subkeyInfo;
this.viewModel = viewModel; this.viewModel = viewModel;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof SubKeyItem && ((SubKeyItem) o).subkeyInfo.key_id() == subkeyInfo.key_id(); return o instanceof SubKeyItem && ((SubKeyItem) o).subkeyInfo.getKey_id() == subkeyInfo.getKey_id();
} }
@Override @Override
public int hashCode() { public int hashCode() {
long key_id = subkeyInfo.key_id(); long key_id = subkeyInfo.getKey_id();
return (int) (key_id ^ (key_id >>> 32)); return (int) (key_id ^ (key_id >>> 32));
} }
@@ -100,13 +100,13 @@ public class SubKeyItem extends AbstractFlexibleItem<SubKeyItem.SubkeyViewHolder
vActionCancel = itemView.findViewById(R.id.button_subkey_action_cancel); vActionCancel = itemView.findViewById(R.id.button_subkey_action_cancel);
} }
void bind(SubKey subkeyInfo) { void bind(Keys subkeyInfo) {
bindKeyId(subkeyInfo.key_id(), subkeyInfo.rank() == 0); bindKeyId(subkeyInfo.getKey_id(), subkeyInfo.getRank() == 0);
bindKeyDetails(subkeyInfo.algorithm(), subkeyInfo.key_size(), subkeyInfo.key_curve_oid(), subkeyInfo.has_secret()); bindKeyDetails(subkeyInfo.getAlgorithm(), subkeyInfo.getKey_size(), subkeyInfo.getKey_curve_oid(), subkeyInfo.getHas_secret());
bindKeyFlags(subkeyInfo.can_certify(), subkeyInfo.can_sign(), subkeyInfo.can_encrypt(), subkeyInfo.can_authenticate()); bindKeyFlags(subkeyInfo.getCan_certify(), subkeyInfo.getCan_sign(), subkeyInfo.getCan_encrypt(), subkeyInfo.getCan_authenticate());
Date validFrom = new Date(subkeyInfo.validFrom() * 1000); Date validFrom = new Date(subkeyInfo.getValidFrom() * 1000);
Date expiryDate = subkeyInfo.expires() ? new Date(subkeyInfo.expiry() * 1000) : null; Date expiryDate = subkeyInfo.getExpiry() != null ? new Date(subkeyInfo.getExpiry() * 1000) : null;
bindKeyStatus(validFrom, expiryDate, subkeyInfo.is_revoked(), subkeyInfo.is_secure()); bindKeyStatus(validFrom, expiryDate, subkeyInfo.is_revoked(), subkeyInfo.is_secure());
} }
@@ -198,14 +198,14 @@ public class SubKeyItem extends AbstractFlexibleItem<SubKeyItem.SubkeyViewHolder
vKeyDetails.setText(algorithmStr); vKeyDetails.setText(algorithmStr);
} }
private void bindSubkeyAction(SubKey subkeyInfo, Builder saveKeyringParcelBuilder) { private void bindSubkeyAction(Keys subkeyInfo, Builder saveKeyringParcelBuilder) {
if (saveKeyringParcelBuilder == null) { if (saveKeyringParcelBuilder == null) {
itemView.setClickable(false); itemView.setClickable(false);
vActionLayout.setVisibility(View.GONE); vActionLayout.setVisibility(View.GONE);
return; return;
} }
boolean isRevokeAction = (saveKeyringParcelBuilder.getMutableRevokeSubKeys().contains(subkeyInfo.key_id())); boolean isRevokeAction = (saveKeyringParcelBuilder.getMutableRevokeSubKeys().contains(subkeyInfo.getKey_id()));
SubkeyChange change = saveKeyringParcelBuilder.getSubkeyChange(subkeyInfo.key_id()); SubkeyChange change = saveKeyringParcelBuilder.getSubkeyChange(subkeyInfo.getKey_id());
boolean hasAction = isRevokeAction || change != null; boolean hasAction = isRevokeAction || change != null;
if (!hasAction) { if (!hasAction) {
itemView.setClickable(true); itemView.setClickable(true);
@@ -214,7 +214,7 @@ public class SubKeyItem extends AbstractFlexibleItem<SubKeyItem.SubkeyViewHolder
} }
OnClickListener onClickRemoveModificationListener = v -> { OnClickListener onClickRemoveModificationListener = v -> {
saveKeyringParcelBuilder.removeModificationsForSubkey(subkeyInfo.key_id()); saveKeyringParcelBuilder.removeModificationsForSubkey(subkeyInfo.getKey_id());
mAdapter.notifyItemChanged(getAdapterPosition()); mAdapter.notifyItemChanged(getAdapterPosition());
}; };

View File

@@ -42,16 +42,15 @@ import androidx.lifecycle.ViewModelProviders;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
import androidx.viewpager.widget.ViewPager.OnPageChangeListener; import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
import com.astuetz.PagerSlidingTabStrip; import com.astuetz.PagerSlidingTabStrip;
import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.livedata.GenericLiveData; import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.SubKey; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UserId;
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@@ -112,7 +111,7 @@ public class ViewKeyAdvActivity extends BaseActivity implements OnPageChangeList
public static class ViewKeyAdvViewModel extends ViewModel { public static class ViewKeyAdvViewModel extends ViewModel {
private Long masterKeyId; private Long masterKeyId;
private LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData; private LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData;
private LiveData<List<SubKey>> subKeyLiveData; private LiveData<List<Keys>> subKeyLiveData;
private LiveData<List<UserId>> userIdsLiveData; private LiveData<List<UserId>> userIdsLiveData;
void setMasterKeyId(long masterKeyId) { void setMasterKeyId(long masterKeyId) {
@@ -134,7 +133,7 @@ public class ViewKeyAdvActivity extends BaseActivity implements OnPageChangeList
return unifiedKeyInfoLiveData; return unifiedKeyInfoLiveData;
} }
LiveData<List<SubKey>> getSubkeyLiveData(Context context) { LiveData<List<Keys>> getSubkeyLiveData(Context context) {
if (subKeyLiveData == null) { if (subKeyLiveData == null) {
KeyRepository keyRepository = KeyRepository.create(context); KeyRepository keyRepository = KeyRepository.create(context);
subKeyLiveData = Transformations.switchMap(getUnifiedKeyInfoLiveData(context), subKeyLiveData = Transformations.switchMap(getUnifiedKeyInfoLiveData(context),

View File

@@ -45,7 +45,7 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.livedata.GenericLiveData; import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.ui.ViewKeyAdvActivity.ViewKeyAdvViewModel; import org.sufficientlysecure.keychain.ui.ViewKeyAdvActivity.ViewKeyAdvViewModel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;

View File

@@ -21,18 +21,11 @@ package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProviders;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.ActionMode; import android.view.ActionMode;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@@ -41,13 +34,20 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ViewAnimator; import android.widget.ViewAnimator;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.FlexibleAdapter.OnItemClickListener; import eu.davidea.flexibleadapter.FlexibleAdapter.OnItemClickListener;
import eu.davidea.flexibleadapter.items.IFlexible; import eu.davidea.flexibleadapter.items.IFlexible;
import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.model.SubKey; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
@@ -99,8 +99,8 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
subkeysList.setAdapter(subkeysAdapter); subkeysList.setAdapter(subkeysAdapter);
ViewKeyAdvViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyAdvViewModel.class); ViewKeyAdvViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyAdvViewModel.class);
viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(this, this::onLoadUnifiedKeyId); viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(getViewLifecycleOwner(), this::onLoadUnifiedKeyId);
viewModel.getSubkeyLiveData(requireContext()).observe(this, this::onLoadSubKeys); viewModel.getSubkeyLiveData(requireContext()).observe(getViewLifecycleOwner(), this::onLoadSubKeys);
subkeyEditViewModel = ViewModelProviders.of(this).get(SubkeyEditViewModel.class); subkeyEditViewModel = ViewModelProviders.of(this).get(SubkeyEditViewModel.class);
} }
@@ -114,9 +114,9 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
subkeyEditViewModel.unifiedKeyInfo = unifiedKeyInfo; subkeyEditViewModel.unifiedKeyInfo = unifiedKeyInfo;
} }
private void onLoadSubKeys(List<SubKey> subKeys) { private void onLoadSubKeys(List<Keys> subKeys) {
ArrayList<IFlexible> subKeyItems = new ArrayList<>(subKeys.size()); ArrayList<IFlexible> subKeyItems = new ArrayList<>(subKeys.size());
for (SubKey subKey : subKeys) { for (Keys subKey : subKeys) {
subKeyItems.add(new SubKeyItem(subKey, subkeyEditViewModel)); subKeyItems.add(new SubKeyItem(subKey, subkeyEditViewModel));
} }
subkeysAdapter.updateDataSet(subKeyItems); subkeysAdapter.updateDataSet(subKeyItems);
@@ -207,7 +207,7 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
} }
private void editSubkey(int position, SubKeyItem item) { private void editSubkey(int position, SubKeyItem item) {
if (subkeyEditViewModel.skpBuilder.hasModificationsForSubkey(item.subkeyInfo.key_id())) { if (subkeyEditViewModel.skpBuilder.hasModificationsForSubkey(item.subkeyInfo.getKey_id())) {
return; return;
} }
@@ -219,8 +219,8 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
editSubkeyExpiry(item); editSubkeyExpiry(item);
break; break;
case EditSubkeyDialogFragment.MESSAGE_REVOKE: case EditSubkeyDialogFragment.MESSAGE_REVOKE:
SubKey subKey = item.subkeyInfo; Keys subKey = item.subkeyInfo;
subkeyEditViewModel.skpBuilder.addRevokeSubkey(subKey.key_id()); subkeyEditViewModel.skpBuilder.addRevokeSubkey(subKey.getKey_id());
break; break;
case EditSubkeyDialogFragment.MESSAGE_STRIP: { case EditSubkeyDialogFragment.MESSAGE_STRIP: {
editSubkeyToggleStrip(item); editSubkeyToggleStrip(item);
@@ -241,21 +241,21 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
} }
private void editSubkeyToggleStrip(SubKeyItem item) { private void editSubkeyToggleStrip(SubKeyItem item) {
SubKey subKey = item.subkeyInfo; Keys subKey = item.subkeyInfo;
if (subKey.has_secret() == SecretKeyType.GNU_DUMMY) { if (subKey.getHas_secret() == SecretKeyType.GNU_DUMMY) {
// Key is already stripped; this is a no-op. // Key is already stripped; this is a no-op.
return; return;
} }
subkeyEditViewModel.skpBuilder.addOrReplaceSubkeyChange(SubkeyChange.createStripChange(subKey.key_id())); subkeyEditViewModel.skpBuilder.addOrReplaceSubkeyChange(SubkeyChange.createStripChange(subKey.getKey_id()));
} }
private void editSubkeyExpiry(SubKeyItem item) { private void editSubkeyExpiry(SubKeyItem item) {
SubKey subKey = item.subkeyInfo; Keys subKey = item.subkeyInfo;
final long keyId = subKey.key_id(); final long keyId = subKey.getKey_id();
final Long creationDate = subKey.creation(); final Long creationDate = subKey.getCreation();
final Long expiryDate = subKey.expiry(); final Long expiryDate = subKey.getExpiry();
Handler returnHandler = new Handler() { Handler returnHandler = new Handler() {
@Override @Override

View File

@@ -20,15 +20,11 @@ package org.sufficientlysecure.keychain.ui;
import java.util.List; import java.util.List;
import androidx.lifecycle.ViewModelProviders;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import android.view.ActionMode; import android.view.ActionMode;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@@ -38,10 +34,14 @@ import android.view.ViewGroup;
import android.widget.ListView; import android.widget.ListView;
import android.widget.ViewAnimator; import android.widget.ViewAnimator;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProviders;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.UserPacket.UserId; import org.sufficientlysecure.keychain.model.UserId;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
@@ -196,8 +196,8 @@ public class ViewKeyAdvUserIdsFragment extends Fragment {
mUserIds.setAdapter(mUserIdsAdapter); mUserIds.setAdapter(mUserIdsAdapter);
ViewKeyAdvViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyAdvViewModel.class); ViewKeyAdvViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyAdvViewModel.class);
viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(this, this::onLoadUnifiedKeyInfo); viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(getViewLifecycleOwner(), this::onLoadUnifiedKeyInfo);
viewModel.getUserIdLiveData(requireContext()).observe(this, this::onLoadUserIds); viewModel.getUserIdLiveData(requireContext()).observe(getViewLifecycleOwner(), this::onLoadUserIds);
} }
public void onLoadUnifiedKeyInfo(UnifiedKeyInfo unifiedKeyInfo) { public void onLoadUnifiedKeyInfo(UnifiedKeyInfo unifiedKeyInfo) {

View File

@@ -14,7 +14,7 @@ import eu.davidea.flexibleadapter.items.IFlexible;
import eu.davidea.viewholders.FlexibleViewHolder; import eu.davidea.viewholders.FlexibleViewHolder;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyDetailsItem.FlexibleKeyItemViewHolder; import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyDetailsItem.FlexibleKeyItemViewHolder;
import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyItem.FlexibleSectionableKeyItem; import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyItem.FlexibleSectionableKeyItem;
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter; import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;

View File

@@ -10,7 +10,7 @@ import android.content.res.Resources;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
public class FlexibleKeyItemFactory { public class FlexibleKeyItemFactory {

View File

@@ -32,9 +32,6 @@ import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.databinding.ImportKeysListItemBinding; import org.sufficientlysecure.keychain.databinding.ImportKeysListItemBinding;
@@ -44,7 +41,7 @@ import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysListener; import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysListener;
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysOperationCallback; import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysOperationCallback;
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysResultListener; import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysResultListener;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.ImportOperation; import org.sufficientlysecure.keychain.operations.ImportOperation;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;

View File

@@ -22,7 +22,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFlexible; import eu.davidea.flexibleadapter.items.IFlexible;
import eu.davidea.viewholders.FlexibleViewHolder; import eu.davidea.viewholders.FlexibleViewHolder;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter.KeyChoiceItem; import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter.KeyChoiceItem;
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter; import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;

View File

@@ -33,7 +33,7 @@ import android.widget.TextView;
import android.widget.ViewAnimator; import android.widget.ViewAnimator;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.UserPacket.UserId; import org.sufficientlysecure.keychain.model.UserId;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;

View File

@@ -7,6 +7,7 @@ import androidx.recyclerview.widget.RecyclerView;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.materialchips.ChipView; import org.sufficientlysecure.materialchips.ChipView;
import org.sufficientlysecure.materialchips.ChipsInput; import org.sufficientlysecure.materialchips.ChipsInput;
import org.sufficientlysecure.materialchips.adapter.ChipsAdapter; import org.sufficientlysecure.materialchips.adapter.ChipsAdapter;
@@ -15,7 +16,6 @@ import org.sufficientlysecure.materialchips.util.ViewUtil;
import org.sufficientlysecure.materialchips.views.DetailedChipView; import org.sufficientlysecure.materialchips.views.DetailedChipView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey;
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipAdapter.ItemViewHolder; import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipAdapter.ItemViewHolder;
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip; import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip;
@@ -63,7 +63,7 @@ public class EncryptRecipientChipAdapter extends ChipsAdapter<EncryptRecipientCh
} }
} }
private SimpleChip simpleChipFromKeyInfo(SubKey.UnifiedKeyInfo keyInfo) { private SimpleChip simpleChipFromKeyInfo(UnifiedKeyInfo keyInfo) {
String name; String name;
String email; String email;
if (keyInfo.name() == null) { if (keyInfo.name() == null) {

View File

@@ -10,7 +10,7 @@ import android.util.AttributeSet;
import org.sufficientlysecure.materialchips.ChipsInput; import org.sufficientlysecure.materialchips.ChipsInput;
import org.sufficientlysecure.materialchips.adapter.FilterableAdapter.FilterableItem; import org.sufficientlysecure.materialchips.adapter.FilterableAdapter.FilterableItem;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip; import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip;

View File

@@ -3,15 +3,15 @@ package org.sufficientlysecure.keychain.ui.keyview;
import java.util.List; import java.util.List;
import android.content.Context;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.Transformations; import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModel;
import android.content.Context; import org.sufficientlysecure.keychain.Key_metadata;
import org.sufficientlysecure.keychain.daos.KeyMetadataDao; import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
import org.sufficientlysecure.keychain.livedata.GenericLiveData; import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.KeyMetadata; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao; import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao;
@@ -21,7 +21,7 @@ import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao.KeySubk
public class KeyFragmentViewModel extends ViewModel { public class KeyFragmentViewModel extends ViewModel {
private LiveData<List<IdentityInfo>> identityInfo; private LiveData<List<IdentityInfo>> identityInfo;
private LiveData<KeySubkeyStatus> subkeyStatus; private LiveData<KeySubkeyStatus> subkeyStatus;
private LiveData<KeyMetadata> keyserverStatus; private LiveData<Key_metadata> keyserverStatus;
LiveData<List<IdentityInfo>> getIdentityInfo(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData) { LiveData<List<IdentityInfo>> getIdentityInfo(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData) {
if (identityInfo == null) { if (identityInfo == null) {
@@ -43,7 +43,7 @@ public class KeyFragmentViewModel extends ViewModel {
return subkeyStatus; return subkeyStatus;
} }
LiveData<KeyMetadata> getKeyserverStatus(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData) { LiveData<Key_metadata> getKeyserverStatus(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData) {
if (keyserverStatus == null) { if (keyserverStatus == null) {
KeyMetadataDao keyMetadataDao = KeyMetadataDao.create(context); KeyMetadataDao keyMetadataDao = KeyMetadataDao.create(context);
keyserverStatus = Transformations.switchMap(unifiedKeyInfoLiveData, keyserverStatus = Transformations.switchMap(unifiedKeyInfoLiveData,

View File

@@ -1,15 +1,15 @@
package org.sufficientlysecure.keychain.ui.keyview; package org.sufficientlysecure.keychain.ui.keyview;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
import org.sufficientlysecure.keychain.livedata.GenericLiveData; import androidx.lifecycle.LiveData;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import androidx.lifecycle.ViewModel;
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager; import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
public class UnifiedKeyInfoViewModel extends ViewModel { public class UnifiedKeyInfoViewModel extends ViewModel {

View File

@@ -70,7 +70,7 @@ import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;

View File

@@ -35,11 +35,11 @@ import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import org.sufficientlysecure.keychain.Key_metadata;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao; import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.model.KeyMetadata; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter; import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
@@ -265,16 +265,16 @@ public class ViewKeyFragment extends Fragment implements OnMenuItemClickListener
identitiesAdapter.setData(identityInfos); identitiesAdapter.setData(identityInfos);
} }
private void onLoadKeyMetadata(KeyMetadata keyMetadata) { private void onLoadKeyMetadata(Key_metadata keyMetadata) {
if (keyMetadata == null) { if (keyMetadata == null) {
keyserverStatusView.setDisplayStatusUnknown(); keyserverStatusView.setDisplayStatusUnknown();
} else if (keyMetadata.hasBeenUpdated()) { } else if (keyMetadata.getLast_updated() != null) {
if (keyMetadata.isPublished()) { if (keyMetadata.getSeen_on_keyservers() != null && keyMetadata.getSeen_on_keyservers()) {
keyserverStatusView.setDisplayStatusPublished(); keyserverStatusView.setDisplayStatusPublished();
} else { } else {
keyserverStatusView.setDisplayStatusNotPublished(); keyserverStatusView.setDisplayStatusNotPublished();
} }
keyserverStatusView.setLastUpdated(keyMetadata.last_updated()); keyserverStatusView.setLastUpdated(keyMetadata.getLast_updated());
} else { } else {
keyserverStatusView.setDisplayStatusUnknown(); keyserverStatusView.setDisplayStatusUnknown();
} }

View File

@@ -22,47 +22,43 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import androidx.sqlite.db.SupportSQLiteDatabase;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import androidx.annotation.Nullable;
import androidx.annotation.Nullable;
import com.google.auto.value.AutoValue; import com.google.auto.value.AutoValue;
import com.squareup.sqldelight.SqlDelightQuery;
import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.keychain.KeychainDatabase; import org.sufficientlysecure.keychain.Autocrypt_peers;
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao; import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.model.AutocryptPeer; import org.sufficientlysecure.keychain.daos.UserIdDao;
import org.sufficientlysecure.keychain.model.UserPacket; import org.sufficientlysecure.keychain.model.UserId;
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
import org.sufficientlysecure.keychain.ui.util.PackageIconGetter; import org.sufficientlysecure.keychain.ui.util.PackageIconGetter;
public class IdentityDao { public class IdentityDao {
private final SupportSQLiteDatabase db;
private final PackageIconGetter packageIconGetter; private final PackageIconGetter packageIconGetter;
private final PackageManager packageManager; private final PackageManager packageManager;
private final AutocryptPeerDao autocryptPeerDao; private final AutocryptPeerDao autocryptPeerDao;
private final UserIdDao userIdDao;
public static IdentityDao getInstance(Context context) { public static IdentityDao getInstance(Context context) {
SupportSQLiteDatabase db = KeychainDatabase.getInstance(context).getWritableDatabase();
PackageManager packageManager = context.getPackageManager(); PackageManager packageManager = context.getPackageManager();
PackageIconGetter iconGetter = PackageIconGetter.getInstance(context); PackageIconGetter iconGetter = PackageIconGetter.getInstance(context);
AutocryptPeerDao autocryptPeerDao = AutocryptPeerDao.getInstance(context); AutocryptPeerDao autocryptPeerDao = AutocryptPeerDao.getInstance(context);
return new IdentityDao(db, packageManager, iconGetter, autocryptPeerDao); UserIdDao userIdDao = UserIdDao.getInstance(context);
return new IdentityDao(packageManager, iconGetter, autocryptPeerDao, userIdDao);
} }
private IdentityDao(SupportSQLiteDatabase db, private IdentityDao(PackageManager packageManager,
PackageManager packageManager, PackageIconGetter iconGetter, PackageIconGetter iconGetter, AutocryptPeerDao autocryptPeerDao,
AutocryptPeerDao autocryptPeerDao) { UserIdDao userIdDao) {
this.db = db;
this.packageManager = packageManager; this.packageManager = packageManager;
this.packageIconGetter = iconGetter; this.packageIconGetter = iconGetter;
this.autocryptPeerDao = autocryptPeerDao; this.autocryptPeerDao = autocryptPeerDao;
this.userIdDao = userIdDao;
} }
public List<IdentityInfo> getIdentityInfos(long masterKeyId) { public List<IdentityInfo> getIdentityInfos(long masterKeyId) {
@@ -74,29 +70,36 @@ public class IdentityDao {
return Collections.unmodifiableList(identities); return Collections.unmodifiableList(identities);
} }
private void correlateOrAddAutocryptPeers(ArrayList<IdentityInfo> identities, long masterKeyId) { private void correlateOrAddAutocryptPeers(ArrayList<IdentityInfo> identities,
for (AutocryptPeer autocryptPeer : autocryptPeerDao.getAutocryptPeersForKey(masterKeyId)) { long masterKeyId) {
String packageName = autocryptPeer.package_name(); for (Autocrypt_peers autocryptPeer : autocryptPeerDao.getAutocryptPeersForKey(
String autocryptId = autocryptPeer.identifier(); masterKeyId)) {
String packageName = autocryptPeer.getPackage_name();
String autocryptId = autocryptPeer.getIdentifier();
Drawable drawable = packageIconGetter.getDrawableForPackageName(packageName); Drawable drawable = packageIconGetter.getDrawableForPackageName(packageName);
Intent autocryptPeerIntent = getAutocryptPeerActivityIntentIfResolvable(packageName, autocryptId); Intent autocryptPeerIntent =
getAutocryptPeerActivityIntentIfResolvable(packageName, autocryptId);
UserIdInfo associatedUserIdInfo = findUserIdMatchingAutocryptPeer(identities, autocryptId); UserIdInfo associatedUserIdInfo =
findUserIdMatchingAutocryptPeer(identities, autocryptId);
if (associatedUserIdInfo != null) { if (associatedUserIdInfo != null) {
int position = identities.indexOf(associatedUserIdInfo); int position = identities.indexOf(associatedUserIdInfo);
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
.create(masterKeyId, associatedUserIdInfo, autocryptId, packageName, drawable, autocryptPeerIntent); .create(masterKeyId, associatedUserIdInfo, autocryptId, packageName,
drawable, autocryptPeerIntent);
identities.set(position, autocryptPeerInfo); identities.set(position, autocryptPeerInfo);
} else { } else {
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
.create(masterKeyId, autocryptId, packageName, drawable, autocryptPeerIntent); .create(masterKeyId, autocryptId, packageName, drawable,
autocryptPeerIntent);
identities.add(autocryptPeerInfo); identities.add(autocryptPeerInfo);
} }
} }
} }
private Intent getAutocryptPeerActivityIntentIfResolvable(String packageName, String autocryptPeer) { private Intent getAutocryptPeerActivityIntentIfResolvable(String packageName,
String autocryptPeer) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction("org.autocrypt.PEER_ACTION"); intent.setAction("org.autocrypt.PEER_ACTION");
intent.setPackage(packageName); intent.setPackage(packageName);
@@ -111,7 +114,8 @@ public class IdentityDao {
} }
} }
private static UserIdInfo findUserIdMatchingAutocryptPeer(List<IdentityInfo> identities, String autocryptPeer) { private static UserIdInfo findUserIdMatchingAutocryptPeer(List<IdentityInfo> identities,
String autocryptPeer) {
for (IdentityInfo identityInfo : identities) { for (IdentityInfo identityInfo : identities) {
if (identityInfo instanceof UserIdInfo) { if (identityInfo instanceof UserIdInfo) {
UserIdInfo userIdInfo = (UserIdInfo) identityInfo; UserIdInfo userIdInfo = (UserIdInfo) identityInfo;
@@ -123,72 +127,90 @@ public class IdentityDao {
return null; return null;
} }
private void loadUserIds(ArrayList<IdentityInfo> identities, long... masterKeyId) { private void loadUserIds(ArrayList<IdentityInfo> identities, long... masterKeyIds) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyId); for (UserId userId : userIdDao.getUserIdsByMasterKeyIds(masterKeyIds)) {
try (Cursor cursor = db.query(query)) { if (userId.name() != null || userId.email() != null) {
while (cursor.moveToNext()) { IdentityInfo identityInfo = UserIdInfo.create(
UserId userId = UserPacket.USER_ID_MAPPER.map(cursor); userId.master_key_id(), userId.rank(), userId.isVerified(),
userId.is_primary(), userId.name(), userId.email(), userId.email());
if (userId.name() != null || userId.email() != null) { identities.add(identityInfo);
IdentityInfo identityInfo = UserIdInfo.create(
userId.master_key_id(), userId.rank(), userId.isVerified(), userId.is_primary(), userId.name(), userId.email(), userId.comment());
identities.add(identityInfo);
}
} }
} }
} }
public interface IdentityInfo { public interface IdentityInfo {
long getMasterKeyId(); long getMasterKeyId();
int getRank(); int getRank();
boolean isVerified(); boolean isVerified();
boolean isPrimary(); boolean isPrimary();
} }
@AutoValue @AutoValue
public abstract static class UserIdInfo implements IdentityInfo { public abstract static class UserIdInfo implements IdentityInfo {
public abstract long getMasterKeyId(); public abstract long getMasterKeyId();
public abstract int getRank(); public abstract int getRank();
public abstract boolean isVerified(); public abstract boolean isVerified();
public abstract boolean isPrimary(); public abstract boolean isPrimary();
@Nullable @Nullable
public abstract String getName(); public abstract String getName();
@Nullable @Nullable
public abstract String getEmail(); public abstract String getEmail();
@Nullable @Nullable
public abstract String getComment(); public abstract String getComment();
static UserIdInfo create(long masterKeyId, int rank, boolean isVerified, boolean isPrimary, String name, String email, static UserIdInfo create(long masterKeyId, int rank, boolean isVerified, boolean isPrimary,
String name, String email,
String comment) { String comment) {
return new AutoValue_IdentityDao_UserIdInfo(masterKeyId, rank, isVerified, isPrimary, name, email, comment); return new AutoValue_IdentityDao_UserIdInfo(masterKeyId, rank, isVerified, isPrimary,
name, email, comment);
} }
} }
@AutoValue @AutoValue
public abstract static class AutocryptPeerInfo implements IdentityInfo { public abstract static class AutocryptPeerInfo implements IdentityInfo {
public abstract long getMasterKeyId(); public abstract long getMasterKeyId();
public abstract int getRank(); public abstract int getRank();
public abstract boolean isVerified(); public abstract boolean isVerified();
public abstract boolean isPrimary(); public abstract boolean isPrimary();
public abstract String getIdentity(); public abstract String getIdentity();
public abstract String getPackageName(); public abstract String getPackageName();
@Nullable @Nullable
public abstract Drawable getAppIcon(); public abstract Drawable getAppIcon();
@Nullable @Nullable
public abstract UserIdInfo getUserIdInfo(); public abstract UserIdInfo getUserIdInfo();
@Nullable @Nullable
public abstract Intent getAutocryptPeerIntent(); public abstract Intent getAutocryptPeerIntent();
static AutocryptPeerInfo create(long masterKeyId, UserIdInfo userIdInfo, String autocryptPeer, String packageName, static AutocryptPeerInfo create(long masterKeyId, UserIdInfo userIdInfo,
String autocryptPeer, String packageName,
Drawable appIcon, Intent autocryptPeerIntent) { Drawable appIcon, Intent autocryptPeerIntent) {
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId, userIdInfo.getRank(), userIdInfo.isVerified(), return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId, userIdInfo.getRank(),
userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo, autocryptPeerIntent); userIdInfo.isVerified(),
userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo,
autocryptPeerIntent);
} }
static AutocryptPeerInfo create(long masterKeyId, String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) { static AutocryptPeerInfo create(long masterKeyId, String autocryptPeer, String packageName,
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId,0, false, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent); Drawable appIcon, Intent autocryptPeerIntent) {
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId, 0, false, false,
autocryptPeer, packageName, appIcon, null, autocryptPeerIntent);
} }
} }

View File

@@ -25,13 +25,13 @@ import java.util.Date;
import java.util.List; import java.util.List;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull;
import org.sufficientlysecure.keychain.model.SubKey; import androidx.annotation.NonNull;
import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants; import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem; import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
import org.sufficientlysecure.keychain.daos.KeyRepository;
public class SubkeyStatusDao { public class SubkeyStatusDao {
@@ -51,7 +51,7 @@ public class SubkeyStatusDao {
SubKeyItem keyCertify = null; SubKeyItem keyCertify = null;
ArrayList<SubKeyItem> keysSign = new ArrayList<>(); ArrayList<SubKeyItem> keysSign = new ArrayList<>();
ArrayList<SubKeyItem> keysEncrypt = new ArrayList<>(); ArrayList<SubKeyItem> keysEncrypt = new ArrayList<>();
for (SubKey subKey : keyRepository.getSubKeysByMasterKeyId(masterKeyId)) { for (Keys subKey : keyRepository.getSubKeysByMasterKeyId(masterKeyId)) {
SubKeyItem ski = new SubKeyItem(masterKeyId, subKey); SubKeyItem ski = new SubKeyItem(masterKeyId, subKey);
if (ski.mKeyId == masterKeyId) { if (ski.mKeyId == masterKeyId) {
@@ -183,23 +183,23 @@ public class SubkeyStatusDao {
final boolean mCanCertify, mCanSign, mCanEncrypt; final boolean mCanCertify, mCanSign, mCanEncrypt;
public final KeySecurityProblem mSecurityProblem; public final KeySecurityProblem mSecurityProblem;
SubKeyItem(long masterKeyId, SubKey subKey) { SubKeyItem(long masterKeyId, Keys subKey) {
mKeyId = subKey.key_id(); mKeyId = subKey.getKey_id();
mCreation = new Date(subKey.creation() * 1000); mCreation = new Date(subKey.getCreation() * 1000);
mSecretKeyType = subKey.has_secret(); mSecretKeyType = subKey.getHas_secret();
mIsRevoked = subKey.is_revoked(); mIsRevoked = subKey.is_revoked();
mExpiry = subKey.expiry() == null ? null : new Date(subKey.expiry() * 1000); mExpiry = subKey.getExpiry() == null ? null : new Date(subKey.getExpiry() * 1000);
mIsExpired = mExpiry != null && mExpiry.before(new Date()); mIsExpired = mExpiry != null && mExpiry.before(new Date());
mCanCertify = subKey.can_certify(); mCanCertify = subKey.getCan_certify();
mCanSign = subKey.can_sign(); mCanSign = subKey.getCan_sign();
mCanEncrypt = subKey.can_encrypt(); mCanEncrypt = subKey.getCan_encrypt();
int algorithm = subKey.algorithm(); int algorithm = subKey.getAlgorithm();
Integer bitStrength = subKey.key_size(); Integer bitStrength = subKey.getKey_size();
String curveOid = subKey.key_curve_oid(); String curveOid = subKey.getKey_curve_oid();
mSecurityProblem = PgpSecurityConstants.getKeySecurityProblem( mSecurityProblem = PgpSecurityConstants.getKeySecurityProblem(
masterKeyId, mKeyId, algorithm, bitStrength, curveOid); masterKeyId, mKeyId, algorithm, bitStrength, curveOid);

View File

@@ -10,8 +10,7 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import java.util.List; import java.util.List;
@@ -150,7 +149,7 @@ public class KeyInfoFormatter {
} }
@NonNull @NonNull
private String getSecretKeyReadableTime(Context context, SubKey.UnifiedKeyInfo keyInfo) { private String getSecretKeyReadableTime(Context context, UnifiedKeyInfo keyInfo) {
long creationMillis = keyInfo.creation() * 1000; long creationMillis = keyInfo.creation() * 1000;
boolean allowRelativeTimestamp = keyInfo.has_duplicate(); boolean allowRelativeTimestamp = keyInfo.has_duplicate();

View File

@@ -1,86 +0,0 @@
/*
* Copyright (C) 2017 Schürmann & Breitmoser GbR
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.widget;
import android.content.Context;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.ViewAnimator;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.Certification.CertDetails;
public class CertListWidget extends ViewAnimator {
private TextView vCollapsed;
private ListView vExpanded;
private View vExpandButton;
public CertListWidget(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
View root = getRootView();
vCollapsed = root.findViewById(R.id.cert_collapsed_list);
vExpanded = root.findViewById(R.id.cert_expanded_list);
vExpandButton = root.findViewById(R.id.cert_expand_button);
// for now
vExpandButton.setVisibility(View.GONE);
vExpandButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
toggleExpanded();
}
});
// vExpanded.setAdapter(null);
}
void toggleExpanded() {
setDisplayedChild(getDisplayedChild() == 1 ? 0 : 1);
}
void setExpanded(boolean expanded) {
setDisplayedChild(expanded ? 1 : 0);
}
public void setData(CertDetails certDetails, boolean isSecret) {
if (certDetails != null) {
CharSequence relativeTimeStr = DateUtils
.getRelativeTimeSpanString(certDetails.creation(), System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_ALL);
if (isSecret) {
vCollapsed.setText("You created this identity " + relativeTimeStr + ".");
} else {
vCollapsed.setText("You verified and confirmed this identity " + relativeTimeStr + ".");
}
} else {
vCollapsed.setText("This identity is not yet verified or confirmed.");
}
}
}

View File

@@ -11,7 +11,7 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter; import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;
import java.util.Arrays; import java.util.Arrays;

View File

@@ -31,7 +31,7 @@ import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
public class KeySpinner extends AppCompatSpinner { public class KeySpinner extends AppCompatSpinner {
public static final String ARG_SUPER_STATE = "super_state"; public static final String ARG_SUPER_STATE = "super_state";

View File

@@ -37,7 +37,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository; import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException; import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.SshPublicKey; import org.sufficientlysecure.keychain.pgp.SshPublicKey;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<org.sufficientlysecure.keychain.ui.widget.CertListWidget
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/linked_id_certs"
tools:showIn="@layout/linked_id_view_fragment">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<TextView
android:id="@+id/cert_collapsed_list"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="center_vertical"
android:layout_weight="1"
tools:text="The identity is not yet verified or confirmed."
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_expand_more_black_24dp"
android:id="@+id/cert_expand_button"
android:padding="4dp"
/>
</LinearLayout>
<ListView
android:id="@+id/cert_expanded_list"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</ListView>
</org.sufficientlysecure.keychain.ui.widget.CertListWidget>

View File

@@ -1,6 +1,6 @@
CREATE TABLE IF NOT EXISTS api_allowed_keys ( CREATE TABLE IF NOT EXISTS api_allowed_keys (
_id INTEGER PRIMARY KEY AUTOINCREMENT, _id INTEGER PRIMARY KEY AUTOINCREMENT,
key_id INTEGER, key_id INTEGER NOT NULL,
package_name TEXT NOT NULL, package_name TEXT NOT NULL,
UNIQUE (key_id, package_name), UNIQUE (key_id, package_name),
FOREIGN KEY (package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE FOREIGN KEY (package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE

View File

@@ -1,16 +1,16 @@
import java.util.Date; import java.util.Date;
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin; import org.sufficientlysecure.keychain.model.GossipOrigin;
CREATE TABLE IF NOT EXISTS autocrypt_peers ( CREATE TABLE IF NOT EXISTS autocrypt_peers (
package_name TEXT NOT NULL, package_name TEXT NOT NULL,
identifier TEXT NOT NULL, identifier TEXT NOT NULL,
last_seen INTEGER AS Date NULL, last_seen INTEGER AS Date,
last_seen_key INTEGER AS Date NULL, last_seen_key INTEGER AS Date,
is_mutual INTEGER AS Boolean NOT NULL DEFAULT 0, is_mutual INTEGER AS Boolean NOT NULL DEFAULT 0,
master_key_id INTEGER NULL, master_key_id INTEGER,
gossip_master_key_id INTEGER NULL, gossip_master_key_id INTEGER,
gossip_last_seen_key INTEGER AS Date NULL, gossip_last_seen_key INTEGER AS Date,
gossip_origin INTEGER AS GossipOrigin NULL, gossip_origin INTEGER AS GossipOrigin,
PRIMARY KEY(package_name, identifier), PRIMARY KEY(package_name, identifier),
FOREIGN KEY(package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE FOREIGN KEY(package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE
); );
@@ -54,10 +54,10 @@ selectAutocryptKeyStatus:
SELECT autocryptPeer.*, SELECT autocryptPeer.*,
(CASE WHEN ac_key.expiry IS NULL THEN 0 WHEN ac_key.expiry > strftime('%s', 'now') THEN 0 ELSE 1 END) AS key_is_expired_int, (CASE WHEN ac_key.expiry IS NULL THEN 0 WHEN ac_key.expiry > strftime('%s', 'now') THEN 0 ELSE 1 END) AS key_is_expired_int,
(CASE WHEN gossip_key.expiry IS NULL THEN 0 WHEN gossip_key.expiry > strftime('%s', 'now') THEN 0 ELSE 1 END) AS gossip_key_is_expired_int, (CASE WHEN gossip_key.expiry IS NULL THEN 0 WHEN gossip_key.expiry > strftime('%s', 'now') THEN 0 ELSE 1 END) AS gossip_key_is_expired_int,
ac_key.is_revoked AS key_is_revoked_int, ac_key.is_revoked AS key_is_revoked,
gossip_key.is_revoked AS gossip_key_is_revoked_int, gossip_key.is_revoked AS gossip_key_is_revoked,
EXISTS (SELECT * FROM certs WHERE certs.master_key_id = autocryptPeer.master_key_id AND verified = 1 ) AS key_is_verified_int, EXISTS (SELECT * FROM certs WHERE certs.master_key_id = autocryptPeer.master_key_id AND verified = 1) AS key_is_verified,
EXISTS (SELECT * FROM certs WHERE certs.master_key_id = autocryptPeer.gossip_master_key_id AND verified = 1 ) AS gossip_key_is_verified_int EXISTS (SELECT * FROM certs WHERE certs.master_key_id = autocryptPeer.gossip_master_key_id AND verified = 1) AS gossip_key_is_verified
FROM autocrypt_peers AS autocryptPeer FROM autocrypt_peers AS autocryptPeer
LEFT JOIN keys AS ac_key ON (ac_key.master_key_id = autocryptPeer.master_key_id AND ac_key.rank = 0) LEFT JOIN keys AS ac_key ON (ac_key.master_key_id = autocryptPeer.master_key_id AND ac_key.rank = 0)
LEFT JOIN keys AS gossip_key ON (gossip_key.master_key_id = gossip_master_key_id AND gossip_key.rank = 0) LEFT JOIN keys AS gossip_key ON (gossip_key.master_key_id = gossip_master_key_id AND gossip_key.rank = 0)

View File

@@ -15,11 +15,11 @@ CREATE TABLE IF NOT EXISTS certs(
); );
insertCert: insertCert:
INSERT INTO certs (master_key_id, rank, key_id_certifier, type, verified, creation, data) VALUES (?, ?, ?, ?, ?, ?, ?); INSERT INTO certs VALUES ?;
selectVerifyingCertDetails: selectVerifyingCertDetails:
SELECT master_key_id AS masterKeyId, key_id_certifier AS signerMasterKeyId, creation * 1000 AS creation SELECT master_key_id AS masterKeyId, key_id_certifier AS signerMasterKeyId, creation * 1000 AS creation
FROM certs FROM certs
WHERE verified = 1 AND master_key_id = ? AND rank = ? WHERE verified = 1 AND master_key_id = ? AND rank = ?
ORDER BY creation DESC ORDER BY certs.creation DESC
LIMIT 1; LIMIT 1;

View File

@@ -16,7 +16,7 @@ SELECT *
deleteAllLastUpdatedTimes: deleteAllLastUpdatedTimes:
UPDATE key_metadata UPDATE key_metadata
SET last_updated = null, seen_on_keyservers = null; SET last_updated = NULL, seen_on_keyservers = NULL;
replaceKeyMetadata: replaceKeyMetadata:
REPLACE INTO key_metadata (master_key_id, last_updated, seen_on_keyservers) VALUES (?, ?, ?); REPLACE INTO key_metadata (master_key_id, last_updated, seen_on_keyservers) VALUES (?, ?, ?);

View File

@@ -1,10 +1,10 @@
CREATE TABLE IF NOT EXISTS keyrings_public ( CREATE TABLE IF NOT EXISTS keyrings_public (
master_key_id INTEGER NOT NULL PRIMARY KEY, master_key_id INTEGER NOT NULL PRIMARY KEY,
key_ring_data BLOB NULL key_ring_data BLOB
); );
insertKeyRingPublic: insertKeyRingPublic:
INSERT INTO keyrings_public (master_key_id, key_ring_data) VALUES (?, ?); INSERT INTO keyrings_public (master_key_id, key_ring_data) VALUES ?;
selectAllMasterKeyIds: selectAllMasterKeyIds:
SELECT master_key_id SELECT master_key_id

View File

@@ -6,7 +6,7 @@ CREATE TABLE IF NOT EXISTS key_signatures (
); );
insertKeySignature: insertKeySignature:
INSERT INTO key_signatures (master_key_id, signer_key_id) VALUES (?, ?); INSERT INTO key_signatures (master_key_id, signer_key_id) VALUES ?;
selectMasterKeyIdsBySigner: selectMasterKeyIdsBySigner:
SELECT master_key_id SELECT master_key_id

View File

@@ -29,7 +29,7 @@ INSERT INTO keys (
master_key_id, rank, key_id, key_size, key_curve_oid, algorithm, fingerprint, master_key_id, rank, key_id, key_size, key_curve_oid, algorithm, fingerprint,
can_certify, can_sign, can_encrypt, can_authenticate, can_certify, can_sign, can_encrypt, can_authenticate,
is_revoked, has_secret, is_secure, creation, expiry, validFrom is_revoked, has_secret, is_secure, creation, expiry, validFrom
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); ) VALUES ?;
updateHasSecretByMasterKeyId: updateHasSecretByMasterKeyId:
UPDATE keys UPDATE keys
@@ -56,11 +56,11 @@ SELECT master_key_id, rank, key_id, key_size, key_curve_oid, algorithm, fingerpr
unifiedKeyView: unifiedKeyView:
CREATE VIEW unifiedKeyView AS CREATE VIEW unifiedKeyView AS
SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.user_id, user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, keys.can_certify, certs.verified, SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.user_id, user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, keys.can_certify, certs.verified,
(EXISTS (SELECT * FROM user_packets AS dups WHERE dups.master_key_id != keys.master_key_id AND dups.rank = 0 AND dups.name = user_packets.name COLLATE NOCASE AND dups.email = user_packets.email COLLATE NOCASE )) AS has_duplicate_int, (EXISTS (SELECT * FROM user_packets AS dups WHERE dups.master_key_id != keys.master_key_id AND dups.rank = 0 AND dups.name = user_packets.name COLLATE NOCASE AND dups.email = user_packets.email COLLATE NOCASE )) AS has_duplicate,
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.has_secret != 0 )) AS has_any_secret_int, (EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.has_secret != 0)) AS has_any_secret,
(SELECT key_id FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_encrypt != 0 LIMIT 1) AS has_encrypt_key_int, (EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_encrypt != 0)) AS has_encrypt_key,
(SELECT key_id FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_sign != 0 LIMIT 1) AS has_sign_key_int, (EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_sign != 0)) AS has_sign_key,
(SELECT key_id FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_authenticate != 0 LIMIT 1) AS has_auth_key_int, (EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_authenticate != 0)) AS has_auth_key,
GROUP_CONCAT(DISTINCT aTI.package_name) AS autocrypt_package_names_csv, GROUP_CONCAT(DISTINCT aTI.package_name) AS autocrypt_package_names_csv,
GROUP_CONCAT(user_packets.user_id, '|||') AS user_id_list GROUP_CONCAT(user_packets.user_id, '|||') AS user_id_list
FROM keys FROM keys
@@ -72,7 +72,7 @@ CREATE VIEW unifiedKeyView AS
selectAllUnifiedKeyInfo: selectAllUnifiedKeyInfo:
SELECT * FROM unifiedKeyView SELECT * FROM unifiedKeyView
ORDER BY has_any_secret_int DESC, IFNULL(name, email) COLLATE NOCASE ASC, creation DESC; ORDER BY has_any_secret DESC, IFNULL(name, email) COLLATE NOCASE ASC, creation DESC;
selectUnifiedKeyInfoByMasterKeyId: selectUnifiedKeyInfoByMasterKeyId:
SELECT * FROM unifiedKeyView SELECT * FROM unifiedKeyView
@@ -89,12 +89,12 @@ SELECT * FROM unifiedKeyView
selectAllUnifiedKeyInfoWithSecret: selectAllUnifiedKeyInfoWithSecret:
SELECT * FROM unifiedKeyView SELECT * FROM unifiedKeyView
WHERE has_any_secret_int = 1 WHERE has_any_secret = 1
ORDER BY creation DESC; ORDER BY creation DESC;
selectAllUnifiedKeyInfoWithAuthKeySecret: selectAllUnifiedKeyInfoWithAuthKeySecret:
SELECT * FROM unifiedKeyView SELECT * FROM unifiedKeyView
WHERE has_any_secret_int = 1 AND has_auth_key_int IS NOT NULL WHERE has_any_secret = 1 AND has_auth_key IS NOT NULL
ORDER BY creation DESC; ORDER BY creation DESC;
selectMasterKeyIdBySubkey: selectMasterKeyIdBySubkey:

View File

@@ -16,8 +16,7 @@ CREATE TABLE IF NOT EXISTS user_packets(
); );
insertUserPacket: insertUserPacket:
INSERT INTO user_packets (master_key_id, rank, type, user_id, name, email, comment, attribute_data, is_primary, is_revoked) INSERT INTO user_packets VALUES ?;
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
selectUserIdsByMasterKeyId: selectUserIdsByMasterKeyId:
SELECT user_packets.master_key_id, user_packets.rank, user_id, name, email, comment, is_primary, is_revoked, MIN(certs.verified) AS verified_int SELECT user_packets.master_key_id, user_packets.rank, user_id, name, email, comment, is_primary, is_revoked, MIN(certs.verified) AS verified_int

View File

@@ -0,0 +1,2 @@
selectChanges:
SELECT changes();

View File

@@ -34,7 +34,7 @@ import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowLog; import org.robolectric.shadows.ShadowLog;
import org.sufficientlysecure.keychain.KeychainTestRunner; import org.sufficientlysecure.keychain.KeychainTestRunner;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;

View File

@@ -27,7 +27,6 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import org.apache.tools.ant.util.StringUtils;
import org.bouncycastle.bcpg.BCPGInputStream; import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.Packet; import org.bouncycastle.bcpg.Packet;
import org.bouncycastle.bcpg.PacketTags; import org.bouncycastle.bcpg.PacketTags;
@@ -388,9 +387,9 @@ public class PgpEncryptDecryptTest {
Assert.assertTrue("verification must succeed", result.success()); Assert.assertTrue("verification must succeed", result.success());
Assert.assertTrue("verification text should equal plaintext (ignoring newlines)", Assert.assertEquals("verification text should equal plaintext (ignoring newlines)",
new String(out.toByteArray()).replace(StringUtils.LINE_SEP, "") out.toString().replace("\r", "").replace("\n", ""),
.equals(plaintext.replace("\r", "").replace("\n", ""))); plaintext.replace("\r", "").replace("\n", ""));
Assert.assertEquals("decryptionResult should be RESULT_NOT_ENCRYPTED", Assert.assertEquals("decryptionResult should be RESULT_NOT_ENCRYPTED",
OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED, result.getDecryptionResult().getResult()); OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED, result.getDecryptionResult().getResult());
Assert.assertEquals("signatureResult should be RESULT_VALID_CONFIRMED", Assert.assertEquals("signatureResult should be RESULT_VALID_CONFIRMED",

View File

@@ -29,7 +29,7 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowLog; import org.robolectric.shadows.ShadowLog;
import org.sufficientlysecure.keychain.KeychainTestRunner; import org.sufficientlysecure.keychain.KeychainTestRunner;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository; import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo; import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
@@ -128,7 +128,6 @@ public class KeyRepositorySaveTest {
CanonicalizedPublicKeyRing pubRing = mDatabaseInteractor.getCanonicalizedPublicKeyRing(keyId); CanonicalizedPublicKeyRing pubRing = mDatabaseInteractor.getCanonicalizedPublicKeyRing(keyId);
Assert.assertEquals("master key should be encryption key", keyId, pubRing.getEncryptId()); Assert.assertEquals("master key should be encryption key", keyId, pubRing.getEncryptId());
Assert.assertEquals("master key should be encryption key (cached)", keyId, unifiedKeyInfo.has_encrypt_key_int());
Assert.assertEquals("canonicalized key flags should be zero", Assert.assertEquals("canonicalized key flags should be zero",
0, (long) pubRing.getPublicKey().getKeyUsage()); 0, (long) pubRing.getPublicKey().getKeyUsage());

View File

@@ -17,15 +17,13 @@ import org.junit.runner.RunWith;
import org.robolectric.Robolectric; import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowBinder; import org.robolectric.shadows.ShadowBinder;
import org.robolectric.shadows.ShadowContentResolver;
import org.robolectric.shadows.ShadowLog; import org.robolectric.shadows.ShadowLog;
import org.robolectric.shadows.ShadowPackageManager; import org.robolectric.shadows.ShadowPackageManager;
import org.sufficientlysecure.keychain.KeychainTestRunner; import org.sufficientlysecure.keychain.KeychainTestRunner;
import org.sufficientlysecure.keychain.daos.ApiAppDao; import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao; import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository; import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.model.ApiApp; import org.sufficientlysecure.keychain.model.GossipOrigin;
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
import org.sufficientlysecure.keychain.operations.CertifyOperation; import org.sufficientlysecure.keychain.operations.CertifyOperation;
import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
@@ -59,8 +57,8 @@ public class KeychainExternalProviderTest {
KeyWritableRepository databaseInteractor = KeyWritableRepository databaseInteractor =
KeyWritableRepository.create(RuntimeEnvironment.application); KeyWritableRepository.create(RuntimeEnvironment.getApplication());
ContentResolver contentResolver = RuntimeEnvironment.application.getContentResolver(); ContentResolver contentResolver = RuntimeEnvironment.getApplication().getContentResolver();
ApiPermissionHelper apiPermissionHelper; ApiPermissionHelper apiPermissionHelper;
ApiAppDao apiAppDao; ApiAppDao apiAppDao;
AutocryptPeerDao autocryptPeerDao; AutocryptPeerDao autocryptPeerDao;
@@ -87,7 +85,7 @@ public class KeychainExternalProviderTest {
apiPermissionHelper = new ApiPermissionHelper(RuntimeEnvironment.application, apiAppDao); apiPermissionHelper = new ApiPermissionHelper(RuntimeEnvironment.application, apiAppDao);
autocryptPeerDao = AutocryptPeerDao.getInstance(RuntimeEnvironment.application); autocryptPeerDao = AutocryptPeerDao.getInstance(RuntimeEnvironment.application);
apiAppDao.insertApiApp(ApiApp.create(PACKAGE_NAME, PACKAGE_SIGNATURE)); apiAppDao.insertApiApp(PACKAGE_NAME, PACKAGE_SIGNATURE);
} }
@Test(expected = AccessControlException.class) @Test(expected = AccessControlException.class)
@@ -104,7 +102,7 @@ public class KeychainExternalProviderTest {
@Test(expected = AccessControlException.class) @Test(expected = AccessControlException.class)
public void testPermission__withWrongPackageCert() throws Exception { public void testPermission__withWrongPackageCert() throws Exception {
apiAppDao.deleteApiApp(PACKAGE_NAME); apiAppDao.deleteApiApp(PACKAGE_NAME);
apiAppDao.insertApiApp(ApiApp.create(PACKAGE_NAME, new byte[] { 1, 2, 4 })); apiAppDao.insertApiApp(PACKAGE_NAME, new byte[] { 1, 2, 4 });
contentResolver.query( contentResolver.query(
AutocryptStatus.CONTENT_URI, AutocryptStatus.CONTENT_URI,

View File

@@ -1,4 +1,8 @@
buildscript { buildscript {
ext {
kotlin_version = '1.8.20'
}
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
@@ -6,8 +10,10 @@ buildscript {
dependencies { dependencies {
// NOTE: Always use fixed version codes not dynamic ones, e.g. 0.7.3 instead of 0.7.+, see README for more information // NOTE: Always use fixed version codes not dynamic ones, e.g. 0.7.3 instead of 0.7.+, see README for more information
classpath 'com.android.tools.build:gradle:4.2.2' classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'com.squareup.sqldelight:gradle-plugin:0.8.0' // classpath 'com.squareup.sqldelight:gradle-plugin:0.8.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.squareup.sqldelight:gradle-plugin:1.5.4'
} }
} }

View File

@@ -1,4 +1,4 @@
android.enableJetifier=true android.enableJetifier=true
android.useAndroidX=true android.useAndroidX=true
android.jetifier.blacklist=bcprov-jdk15on android.jetifier.ignorelist=bcprov-jdk15on
org.gradle.jvmargs=-Xms128m -Xmx4096m -XX:+CMSClassUnloadingEnabled org.gradle.jvmargs=-Xms128m -Xmx4096m -XX:+CMSClassUnloadingEnabled

Some files were not shown because too many files have changed in this diff Show More