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
# omit for now:
fastlane/Appfile
fastlane/Appfile
OpenKeychain/release
OpenKeychain/google

View File

@ -1,5 +1,8 @@
apply plugin: 'com.android.application'
apply plugin: 'com.squareup.sqldelight'
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'com.squareup.sqldelight'
}
dependencies {
// from local Android SDK
@ -20,6 +23,7 @@ dependencies {
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-dom:0.8.1'
implementation "com.squareup.sqldelight:android-driver:1.5.4"
// UI
implementation 'org.sufficientlysecure:html-textview:3.1'
@ -86,6 +90,7 @@ dependencies {
android {
compileSdkVersion rootProject.ext.compileSdkVersion
namespace 'org.sufficientlysecure.keychain'
defaultConfig {
minSdkVersion 15

View File

@ -23,17 +23,15 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.Context;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.sqlite.db.SupportSQLiteOpenHelper;
import androidx.sqlite.db.SupportSQLiteOpenHelper.Callback;
import androidx.sqlite.db.SupportSQLiteOpenHelper.Configuration;
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteException;
import org.sufficientlysecure.keychain.daos.LocalSecretKeyStorage;
import com.squareup.sqldelight.android.AndroidSqliteDriver;
import org.sufficientlysecure.keychain.model.CustomColumnAdapters;
import org.sufficientlysecure.keychain.util.Preferences;
import timber.log.Timber;
@ -41,15 +39,18 @@ import timber.log.Timber;
/**
* SQLite Datatypes (from http://www.sqlite.org/datatype3.html)
* - 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.
* - 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.
*/
public class KeychainDatabase {
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 Database sqldelightDatabase;
private static KeychainDatabase sInstance;
@ -71,12 +72,15 @@ public class KeychainDatabase {
}
@Override
public void onUpgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
KeychainDatabase.this.onUpgrade(db, context, oldVersion, newVersion);
public void onUpgrade(SupportSQLiteDatabase db, int oldVersion,
int newVersion) {
KeychainDatabase.this.onUpgrade(db, context, oldVersion,
newVersion);
}
@Override
public void onDowngrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
public void onDowngrade(SupportSQLiteDatabase db,
int oldVersion, int newVersion) {
KeychainDatabase.this.onDowngrade();
}
@ -86,12 +90,19 @@ public class KeychainDatabase {
if (!db.isReadOnly()) {
// Enable foreign key constraints
db.execSQL("PRAGMA foreign_keys=ON;");
if (Constants.DEBUG) {
recreateUnifiedKeyView(db);
}
}
}
}).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() {
@ -102,328 +113,85 @@ public class KeychainDatabase {
return supportSQLiteOpenHelper.getWritableDatabase();
}
public Database getSqlDelightDatabase() {
return sqldelightDatabase;
}
@SuppressWarnings("deprecation") // using some sqldelight constants
private void onCreate(SupportSQLiteDatabase db, Context context) {
Timber.w("Creating database...");
db.execSQL(KeyRingsPublicModel.CREATE_TABLE);
db.execSQL(KeysModel.CREATE_TABLE);
db.execSQL(UserPacketsModel.CREATE_TABLE);
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);
AndroidSqliteDriver sqlDriver = new AndroidSqliteDriver(db);
Database.Companion.getSchema().create(sqlDriver);
recreateDatabaseViews(db);
db.execSQL("CREATE INDEX keys_by_rank ON keys (" + KeysModel.RANK + ", " + KeysModel.MASTER_KEY_ID + ");");
db.execSQL("CREATE INDEX uids_by_rank ON user_packets (" + UserPacketsModel.RANK + ", "
+ UserPacketsModel.USER_ID + ", " + UserPacketsModel.MASTER_KEY_ID + ");");
db.execSQL("CREATE INDEX verified_certs ON certs ("
+ CertsModel.VERIFIED + ", " + CertsModel.MASTER_KEY_ID + ");");
db.execSQL("CREATE INDEX uids_by_email ON user_packets ("
+ UserPacketsModel.EMAIL + ");");
db.execSQL("CREATE INDEX keys_by_rank ON keys (rank, master_key_id);");
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);");
db.execSQL("CREATE INDEX uids_by_email ON user_packets (email);");
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);
if (oldVersion < 34) {
throw new IllegalStateException("upgrades from older versions not supported");
}
switch (oldVersion) {
case 1:
// add has_secret for all who are upgrading from a beta version
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);
case 34:
// nothing
}
// recreate the unified key view on any upgrade
recreateDatabaseViews(db);
}
private void addSubkeyValidFromField(SupportSQLiteDatabase db) {
try {
db.execSQL("ALTER TABLE keys ADD COLUMN validFrom INTEGER NOT NULL DEFAULT 0;");
db.execSQL("UPDATE keys SET validFrom = creation");
} catch (SQLiteException e) {
// column probably already existed, nvm this
}
}
private static void recreateDatabaseViews(SupportSQLiteDatabase db) {
// for some reason those aren't created as part of the schema. so we do it here.
db.execSQL("DROP VIEW IF EXISTS unifiedKeyView");
db.execSQL(
"""
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() {
@ -468,7 +236,7 @@ public class KeychainDatabase {
out.createNewFile();
}
if (!in.canRead()) {
throw new IOException("Cannot read " + in.getName());
throw new IOException("Cannot read " + in.getName());
}
if (!out.canWrite()) {
throw new IOException("Cannot write " + out.getName());

View File

@ -1,16 +1,9 @@
package org.sufficientlysecure.keychain.daos;
import java.util.ArrayList;
import java.util.List;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.sqlite.db.SupportSQLiteQuery;
import android.database.Cursor;
import com.squareup.sqldelight.RowMapper;
import org.sufficientlysecure.keychain.Database;
import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
class AbstractDao {
@ -22,8 +15,8 @@ class AbstractDao {
this.databaseNotifyManager = databaseNotifyManager;
}
SupportSQLiteDatabase getReadableDb() {
return db.getReadableDatabase();
Database getDatabase() {
return db.getSqlDelightDatabase();
}
SupportSQLiteDatabase getWritableDb() {
@ -33,32 +26,4 @@ class AbstractDao {
DatabaseNotifyManager getDatabaseNotifyManager() {
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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import android.content.Context;
import android.database.Cursor;
import com.squareup.sqldelight.SqlDelightQuery;
import org.sufficientlysecure.keychain.ApiAllowedKeysModel.InsertAllowedKey;
import org.sufficientlysecure.keychain.ApiAppsModel;
import org.sufficientlysecure.keychain.ApiAppsModel.DeleteByPackageName;
import org.sufficientlysecure.keychain.ApiAppsModel.InsertApiApp;
import org.sufficientlysecure.keychain.ApiAllowedKeysQueries;
import org.sufficientlysecure.keychain.ApiAppsQueries;
import org.sufficientlysecure.keychain.Api_apps;
import org.sufficientlysecure.keychain.GetCertificate;
import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.model.ApiAllowedKey;
import org.sufficientlysecure.keychain.model.ApiApp;
public class ApiAppDao extends AbstractDao {
private final ApiAppsQueries apiAppsQueries = getDatabase().getApiAppsQueries();
private final ApiAllowedKeysQueries apiAllowedKeysQueries =
getDatabase().getApiAllowedKeysQueries();
public static ApiAppDao getInstance(Context context) {
KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context);
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
@ -45,95 +44,75 @@ public class ApiAppDao extends AbstractDao {
return new ApiAppDao(keychainDatabase, databaseNotifyManager);
}
private ApiAppDao(KeychainDatabase keychainDatabase, DatabaseNotifyManager databaseNotifyManager) {
private ApiAppDao(KeychainDatabase keychainDatabase,
DatabaseNotifyManager databaseNotifyManager) {
super(keychainDatabase, databaseNotifyManager);
}
public ApiApp getApiApp(String packageName) {
try (Cursor cursor = getReadableDb().query(ApiApp.FACTORY.selectByPackageName(packageName))) {
if (cursor.moveToFirst()) {
return ApiApp.FACTORY.selectByPackageNameMapper().map(cursor);
}
return null;
}
public Api_apps getApiApp(String packageName) {
return apiAppsQueries.selectByPackageName(packageName).executeAsOneOrNull();
}
public byte[] getApiAppCertificate(String packageName) {
try (Cursor cursor = getReadableDb().query(ApiApp.FACTORY.getCertificate(packageName))) {
if (cursor.moveToFirst()) {
return ApiApp.FACTORY.getCertificateMapper().map(cursor);
}
GetCertificate getCertificate =
apiAppsQueries.getCertificate(packageName).executeAsOneOrNull();
if (getCertificate == null) {
return null;
}
return getCertificate.getPackage_signature();
}
public void insertApiApp(ApiApp apiApp) {
ApiApp existingApiApp = getApiApp(apiApp.package_name());
public void insertApiApp(String packageName, byte[] signature) {
Api_apps existingApiApp = getApiApp(packageName);
if (existingApiApp != null) {
if (!Arrays.equals(existingApiApp.package_signature(), apiApp.package_signature())) {
throw new IllegalStateException("Inserting existing api with different signature?!");
if (!Arrays.equals(existingApiApp.getPackage_signature(),
signature)) {
throw new IllegalStateException(
"Inserting existing api with different signature?!");
}
return;
}
InsertApiApp statement = new ApiAppsModel.InsertApiApp(getWritableDb());
statement.bind(apiApp.package_name(), apiApp.package_signature());
statement.executeInsert();
apiAppsQueries.insertApiApp(packageName, signature);
getDatabaseNotifyManager().notifyApiAppChange(packageName);
}
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) {
DeleteByPackageName deleteByPackageName = new DeleteByPackageName(getWritableDb());
deleteByPackageName.bind(packageName);
deleteByPackageName.executeUpdateDelete();
apiAppsQueries.deleteByPackageName(packageName);
getDatabaseNotifyManager().notifyApiAppChange(packageName);
}
public HashSet<Long> getAllowedKeyIdsForApp(String packageName) {
SqlDelightQuery allowedKeys = ApiAllowedKey.FACTORY.getAllowedKeys(packageName);
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;
return new HashSet<>(apiAllowedKeysQueries.getAllowedKeys(packageName).executeAsList());
}
public void saveAllowedKeyIdsForApp(String packageName, Set<Long> allowedKeyIds) {
ApiAllowedKey.DeleteByPackageName deleteByPackageName = new ApiAllowedKey.DeleteByPackageName(getWritableDb());
deleteByPackageName.bind(packageName);
deleteByPackageName.executeUpdateDelete();
InsertAllowedKey statement = new InsertAllowedKey(getWritableDb());
apiAllowedKeysQueries.deleteByPackageName(packageName);
for (Long keyId : allowedKeyIds) {
statement.bind(packageName, keyId);
statement.execute();
apiAllowedKeysQueries.insertAllowedKey(packageName, keyId);
}
getDatabaseNotifyManager().notifyApiAppChange(packageName);
}
public void addAllowedKeyIdForApp(String packageName, long allowedKeyId) {
InsertAllowedKey statement = new InsertAllowedKey(getWritableDb());
statement.bind(packageName, allowedKeyId);
statement.executeInsert();
apiAllowedKeysQueries.insertAllowedKey(packageName, allowedKeyId);
getDatabaseNotifyManager().notifyApiAppChange(packageName);
}
public List<ApiApp> getAllApiApps() {
SqlDelightQuery query = ApiApp.FACTORY.selectAll();
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;
public List<Api_apps> getAllApiApps() {
return apiAppsQueries.selectAll().executeAsList();
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -20,22 +20,23 @@ package org.sufficientlysecure.keychain.daos;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
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.sufficientlysecure.keychain.KeyRingsPublicQueries;
import org.sufficientlysecure.keychain.KeySignaturesQueries;
import org.sufficientlysecure.keychain.KeychainDatabase;
import org.sufficientlysecure.keychain.model.Certification;
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.model.UserPacket.UserId;
import org.sufficientlysecure.keychain.Keyrings_public;
import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.KeysQueries;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.UserId;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
@ -49,9 +50,12 @@ import timber.log.Timber;
public class KeyRepository extends AbstractDao {
final LocalPublicKeyStorage mLocalPublicKeyStorage;
final LocalSecretKeyStorage localSecretKeyStorage;
private final KeysQueries keysQueries = getDatabase().getKeysQueries();
OperationLog mLog;
int mIndent;
private final KeyRingsPublicQueries keyRingsPublicQueries = getDatabase().getKeyRingsPublicQueries();
private final KeySignaturesQueries keySignaturesQueries = getDatabase().getKeySignaturesQueries();
public static KeyRepository create(Context context) {
LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context);
@ -59,14 +63,16 @@ public class KeyRepository extends AbstractDao {
KeychainDatabase database = KeychainDatabase.getInstance(context);
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
return new KeyRepository(database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage);
return new KeyRepository(database, databaseNotifyManager, localPublicKeyStorage,
localSecretKeyStorage);
}
private KeyRepository(KeychainDatabase database,
DatabaseNotifyManager databaseNotifyManager,
LocalPublicKeyStorage localPublicKeyStorage,
LocalSecretKeyStorage localSecretKeyStorage) {
this(database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage, new OperationLog(), 0);
this(database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage,
new OperationLog(), 0);
}
KeyRepository(KeychainDatabase database,
@ -101,7 +107,8 @@ public class KeyRepository extends AbstractDao {
mLog = new OperationLog();
}
public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long masterKeyId) throws NotFoundException {
public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long masterKeyId)
throws NotFoundException {
UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
if (unifiedKeyInfo == null) {
throw new NotFoundException();
@ -111,7 +118,8 @@ public class KeyRepository extends AbstractDao {
return new CanonicalizedPublicKeyRing(publicKeyData, unifiedKeyInfo.verified());
}
public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(long masterKeyId) throws NotFoundException {
public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(long masterKeyId)
throws NotFoundException {
UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
if (unifiedKeyInfo == null || !unifiedKeyInfo.has_any_secret()) {
throw new NotFoundException();
@ -124,75 +132,85 @@ public class KeyRepository extends AbstractDao {
}
public List<Long> getAllMasterKeyIds() {
SqlDelightQuery query = KeyRingPublic.FACTORY.selectAllMasterKeyIds();
return mapAllRows(query, KeySignature.FACTORY.selectMasterKeyIdsBySignerMapper());
return keyRingsPublicQueries.selectAllMasterKeyIds().executeAsList();
}
public List<Long> getMasterKeyIdsBySigner(List<Long> signerMasterKeyIds) {
long[] signerKeyIds = getLongListAsArray(signerMasterKeyIds);
SqlDelightQuery query = KeySignature.FACTORY.selectMasterKeyIdsBySigner(signerKeyIds);
return mapAllRows(query, KeySignature.FACTORY.selectMasterKeyIdsBySignerMapper());
return keySignaturesQueries.selectMasterKeyIdsBySigner(signerMasterKeyIds).executeAsList();
}
public Long getMasterKeyIdBySubkeyId(long subKeyId) {
SqlDelightQuery query = SubKey.FACTORY.selectMasterKeyIdBySubkey(subKeyId);
return mapSingleRow(query, SubKey.FACTORY.selectMasterKeyIdBySubkeyMapper());
return keysQueries.selectMasterKeyIdBySubkey(subKeyId).executeAsOneOrNull();
}
public UnifiedKeyInfo getUnifiedKeyInfo(long masterKeyId) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyId(masterKeyId);
return mapSingleRow(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
return keysQueries.selectUnifiedKeyInfoByMasterKeyId(masterKeyId, UnifiedKeyInfo::create).executeAsOneOrNull();
}
public List<UnifiedKeyInfo> getUnifiedKeyInfo(long... masterKeyIds) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyIds(masterKeyIds);
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
return keysQueries.selectUnifiedKeyInfoByMasterKeyIds(getLongArrayAsList(masterKeyIds), UnifiedKeyInfo::create)
.executeAsList();
}
public List<UnifiedKeyInfo> getUnifiedKeyInfosByMailAddress(String mailAddress) {
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%');
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
return keysQueries.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%', UnifiedKeyInfo::create)
.executeAsList();
}
public List<UnifiedKeyInfo> getAllUnifiedKeyInfo() {
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfo();
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
return keysQueries.selectAllUnifiedKeyInfo(UnifiedKeyInfo::create).executeAsList();
}
public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithSecret() {
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfoWithSecret();
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
return keysQueries.selectAllUnifiedKeyInfoWithSecret(UnifiedKeyInfo::create).executeAsList();
}
public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithAuthKeySecret() {
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfoWithAuthKeySecret();
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
return keysQueries.selectAllUnifiedKeyInfoWithAuthKeySecret(UnifiedKeyInfo::create).executeAsList();
}
public List<UserId> getUserIds(long... masterKeyIds) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyIds);
return mapAllRows(query, UserPacket.USER_ID_MAPPER);
return getDatabase().getUserPacketsQueries()
.selectUserIdsByMasterKeyId(getLongArrayAsList(masterKeyIds), UserId::create).executeAsList();
}
public List<String> getConfirmedUserIds(long masterKeyId) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyIdAndVerification(
Certification.FACTORY, masterKeyId, VerificationStatus.VERIFIED_SECRET);
return mapAllRows(query, cursor -> UserPacket.USER_ID_MAPPER.map(cursor).user_id());
return getDatabase().getUserPacketsQueries()
.selectUserIdsByMasterKeyIdAndVerification(masterKeyId,
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) {
SqlDelightQuery query = SubKey.FACTORY.selectSubkeysByMasterKeyId(masterKeyId);
return mapAllRows(query, SubKey.SUBKEY_MAPPER);
public List<Keys> getSubKeysByMasterKeyId(long masterKeyId) {
return keysQueries.selectSubkeysByMasterKeyId(masterKeyId).executeAsList();
}
public SecretKeyType getSecretKeyType(long keyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectSecretKeyType(keyId);
return mapSingleRowOrThrow(query, SubKey.SKT_MAPPER);
try {
return keysQueries.selectSecretKeyType(keyId).executeAsOne();
} catch (NullPointerException npe) {
throw new NotFoundException();
}
}
public byte[] getFingerprintByKeyId(long keyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectFingerprintByKeyId(keyId);
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectFingerprintByKeyIdMapper());
try {
return keysQueries.selectFingerprintByKeyId(keyId).executeAsOne();
} catch (NullPointerException npe) {
throw new NotFoundException();
}
}
private byte[] getKeyRingAsArmoredData(byte[] data) throws IOException {
@ -205,23 +223,26 @@ public class KeyRepository extends AbstractDao {
return bos.toByteArray();
}
public String getPublicKeyRingAsArmoredString(long masterKeyId) throws NotFoundException, IOException {
public String getPublicKeyRingAsArmoredString(long masterKeyId)
throws NotFoundException, IOException {
byte[] data = loadPublicKeyRingData(masterKeyId);
byte[] armoredData = getKeyRingAsArmoredData(data);
return new String(armoredData);
}
public byte[] getSecretKeyRingAsArmoredData(long masterKeyId) throws NotFoundException, IOException {
public byte[] getSecretKeyRingAsArmoredData(long masterKeyId)
throws NotFoundException, IOException {
byte[] data = loadSecretKeyRingData(masterKeyId);
return getKeyRingAsArmoredData(data);
}
public final byte[] loadPublicKeyRingData(long masterKeyId) throws NotFoundException {
SqlDelightQuery query = KeyRingPublic.FACTORY.selectByMasterKeyId(masterKeyId);
try (Cursor cursor = getReadableDb().query(query)) {
if (cursor.moveToFirst()) {
KeyRingPublic keyRingPublic = KeyRingPublic.MAPPER.map(cursor);
byte[] keyRingData = keyRingPublic.key_ring_data();
Query<Keyrings_public> keyringsPublicQuery =
keyRingsPublicQueries.selectByMasterKeyId(masterKeyId);
try (SqlCursor cursor = keyringsPublicQuery.execute()) {
if (cursor.next()) {
Keyrings_public keyRingPublic = keyringsPublicQuery.getMapper().invoke(cursor);
byte[] keyRingData = keyRingPublic.getKey_ring_data();
if (keyRingData == null) {
keyRingData = mLocalPublicKeyStorage.readPublicKey(masterKeyId);
}
@ -243,18 +264,16 @@ public class KeyRepository extends AbstractDao {
}
public long getSecretSignId(long masterKeyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyId(masterKeyId);
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyIdMapper());
return keysQueries.selectEffectiveSignKeyIdByMasterKeyId(masterKeyId).executeAsOneOrNull();
}
public long getEffectiveAuthenticationKeyId(long masterKeyId) throws NotFoundException {
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyId(masterKeyId);
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyIdMapper());
return keysQueries.selectEffectiveAuthKeyIdByMasterKeyId(masterKeyId).executeAsOneOrNull();
}
public List<Long> getPublicEncryptionIds(long masterKeyId) {
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveEncryptionKeyIdsByMasterKeyId(masterKeyId);
return mapAllRows(query, SubKey.FACTORY.selectEffectiveEncryptionKeyIdsByMasterKeyIdMapper());
return keysQueries.selectEffectiveEncryptionKeyIdsByMasterKeyId(masterKeyId)
.executeAsList();
}
public static class NotFoundException extends Exception {
@ -274,4 +293,13 @@ public class KeyRepository extends AbstractDao {
}
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.List;
import androidx.sqlite.db.SupportSQLiteDatabase;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.collection.LongSparseArray;
import androidx.sqlite.db.SupportSQLiteDatabase;
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.KeysModel.UpdateHasSecretByKeyId;
import org.sufficientlysecure.keychain.KeysModel.UpdateHasSecretByMasterKeyId;
import org.sufficientlysecure.keychain.Keyrings_public;
import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.KeysQueries;
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.model.Certification;
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.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
@ -114,7 +113,7 @@ public class KeyWritableRepository extends KeyRepository {
this.context = context;
this.databaseNotifyManager = databaseNotifyManager;
this.autocryptPeerDao = autocryptPeerDao;
this.databaseBatchInteractor = new DatabaseBatchInteractor(getWritableDb());
this.databaseBatchInteractor = new DatabaseBatchInteractor(getDatabase());
}
private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() {
@ -193,7 +192,7 @@ public class KeyWritableRepository extends KeyRepository {
log(LogType.MSG_IP_INSERT_KEYRING);
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));
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(),
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));
++rank;
@ -300,7 +302,7 @@ public class KeyWritableRepository extends KeyRepository {
// keep a note about the issuer of this key signature
if (!signerKeyIds.contains(certId)) {
KeySignature keySignature = KeySignature.create(masterKeyId, certId);
Key_signatures keySignature = new Key_signatures(masterKeyId, certId);
operations.add(DatabaseBatchInteractor.createInsertSignerKey(keySignature));
signerKeyIds.add(certId);
}
@ -468,7 +470,7 @@ public class KeyWritableRepository extends KeyRepository {
for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) {
UserPacketItem item = uids.get(userIdRank);
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);
operations.add(DatabaseBatchInteractor.createInsertUserPacket(userPacket));
@ -508,14 +510,13 @@ public class KeyWritableRepository extends KeyRepository {
mIndent -= 1;
}
SupportSQLiteDatabase db = databaseBatchInteractor.getDb();
SupportSQLiteDatabase db = getWritableDb();
try {
db.beginTransaction();
// delete old version of this keyRing (from database only!), which also deletes all keys and userIds on cascade
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(db);
deleteStatement.bind(masterKeyId);
int deletedRows = deleteStatement.executeUpdateDelete();
getDatabase().getKeyRingsPublicQueries().deleteByMasterKeyId(masterKeyId);
int deletedRows = getDatabase().getUtilQueries().selectChanges().executeAsOne().intValue();
if (deletedRows > 0) {
log(LogType.MSG_IP_DELETE_OLD_OK);
@ -559,9 +560,8 @@ public class KeyWritableRepository extends KeyRepository {
}
autocryptPeerDao.deleteByMasterKeyId(masterKeyId);
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(getWritableDb());
deleteStatement.bind(masterKeyId);
int deletedRows = deleteStatement.executeUpdateDelete();
getDatabase().getKeyRingsPublicQueries().deleteByMasterKeyId(masterKeyId);
int deletedRows = getDatabase().getUtilQueries().selectChanges().executeAsOne().intValue();
databaseNotifyManager.notifyKeyChange(masterKeyId);
@ -631,12 +631,10 @@ public class KeyWritableRepository extends KeyRepository {
}
{
UpdateHasSecretByMasterKeyId resetStatement =
SubKey.createUpdateHasSecretByMasterKeyIdStatement(getWritableDb());
resetStatement.bind(masterKeyId, SecretKeyType.GNU_DUMMY);
resetStatement.executeUpdateDelete();
KeysQueries keysQueries = getDatabase().getKeysQueries();
UtilQueries utilQueries = getDatabase().getUtilQueries();
UpdateHasSecretByKeyId updateStatement = SubKey.createUpdateHasSecretByKeyId(getWritableDb());
keysQueries.updateHasSecretByMasterKeyId(masterKeyId, SecretKeyType.GNU_DUMMY);
// then, mark exactly the keys we have available
log(LogType.MSG_IS_IMPORTING_SUBKEYS);
@ -644,8 +642,8 @@ public class KeyWritableRepository extends KeyRepository {
for (CanonicalizedSecretKey sub : keyRing.secretKeyIterator()) {
long id = sub.getKeyId();
SecretKeyType mode = sub.getSecretKeyTypeSuperExpensive();
updateStatement.bind(id, mode);
int upd = updateStatement.executeUpdateDelete();
keysQueries.updateHasSecretByKeyId(id, mode);
int upd = utilQueries.selectChanges().executeAsOne().intValue();
if (upd == 1) {
switch (mode) {
case PASSPHRASE:
@ -1013,8 +1011,9 @@ public class KeyWritableRepository extends KeyRepository {
private BatchOp buildCertOperations(long masterKeyId, int rank, WrappedSignature cert, VerificationStatus verificationStatus) {
try {
Certification certification = Certification.create(masterKeyId, rank, cert.getKeyId(),
cert.getSignatureType(), verificationStatus, cert.getCreationTime(), cert.getEncoded());
long creationUnixTime = cert.getCreationTime().getTime() / 1000;
Certs certification = new Certs(masterKeyId, rank, cert.getKeyId(),
cert.getSignatureType(), verificationStatus, creationUnixTime, cert.getEncoded());
return DatabaseBatchInteractor.createInsertCertification(certification);
} catch (IOException e) {
throw new AssertionError(e);

View File

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

View File

@ -1,16 +1,19 @@
package org.sufficientlysecure.keychain.daos;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.model.UserPacket;
import org.sufficientlysecure.keychain.model.UserPacket.UidStatus;
import org.sufficientlysecure.keychain.UidStatus;
import org.sufficientlysecure.keychain.model.UserId;
public class UserIdDao extends AbstractDao {
@ -25,20 +28,38 @@ public class UserIdDao extends AbstractDao {
super(db, databaseNotifyManager);
}
public UidStatus getUidStatusByEmailLike(String emailLike) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdStatusByEmailLike(emailLike);
return mapSingleRow(query, UserPacket.UID_STATUS_MAPPER);
public List<UserId> getUserIdsByMasterKeyIds(long... masterKeyIds) {
return getDatabase().getUserPacketsQueries()
.selectUserIdsByMasterKeyId(getLongArrayAsList(masterKeyIds), UserId::create)
.executeAsList();
}
public Map<String,UidStatus> getUidStatusByEmail(String... emails) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdStatusByEmail(emails);
Map<String,UidStatus> result = new HashMap<>();
try (Cursor cursor = getReadableDb().query(query)) {
while (cursor.moveToNext()) {
UidStatus item = UserPacket.UID_STATUS_MAPPER.map(cursor);
result.put(item.email(), item);
public UidStatus getUidStatusByEmailLike(String emailLike) {
return getDatabase().getUserPacketsQueries().selectUserIdStatusByEmailLike(emailLike)
.executeAsOne();
}
public Map<String, UidStatus> getUidStatusByEmail(String... emails) {
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;
}
}
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.graphics.drawable.Drawable;
import org.sufficientlysecure.keychain.Api_apps;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
import org.sufficientlysecure.keychain.livedata.ApiAppsLiveData.ListedApp;
import org.sufficientlysecure.keychain.model.ApiApp;
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) {
List<ApiApp> registeredApiApps = apiAppDao.getAllApiApps();
List<Api_apps> registeredApiApps = apiAppDao.getAllApiApps();
for (ApiApp apiApp : registeredApiApps) {
for (Api_apps apiApp : registeredApiApps) {
ListedApp listedApp;
try {
ApplicationInfo ai = packageManager.getApplicationInfo(apiApp.package_name(), 0);
ApplicationInfo ai = packageManager.getApplicationInfo(apiApp.getPackage_name(), 0);
CharSequence applicationLabel = packageManager.getApplicationLabel(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) {
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);
}

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 androidx.annotation.NonNull;
import com.squareup.sqldelight.ColumnAdapter;
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
@ -15,7 +13,7 @@ public final class 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
@Override
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
@Override
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.daos.KeyRepository;
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.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;

View File

@ -21,7 +21,7 @@ package org.sufficientlysecure.keychain.operations;
import android.content.Context;
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.OperationResult;
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.util.OpenPgpUtils;
import org.openintents.openpgp.util.OpenPgpUtils.UserId;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import timber.log.Timber;

View File

@ -8,20 +8,20 @@ import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import androidx.annotation.Nullable;
import android.text.format.DateUtils;
import androidx.annotation.Nullable;
import org.openintents.openpgp.AutocryptPeerUpdate;
import org.openintents.openpgp.AutocryptPeerUpdate.PreferEncrypt;
import org.sufficientlysecure.keychain.Autocrypt_peers;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.model.AutocryptPeer;
import org.sufficientlysecure.keychain.model.AutocryptPeer.AutocryptKeyStatus;
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
import org.sufficientlysecure.keychain.SelectAutocryptKeyStatus;
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.model.GossipOrigin;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import timber.log.Timber;
@ -48,17 +48,17 @@ public class AutocryptInteractor {
}
void updateAutocryptPeerState(String autocryptPeerId, AutocryptPeerUpdate autocryptPeerUpdate) {
AutocryptPeer currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId);
Autocrypt_peers currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId);
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.
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) {
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.
Date lastSeen = currentAutocryptPeer != null ? currentAutocryptPeer.last_seen() : null;
Date lastSeen = currentAutocryptPeer != null ? currentAutocryptPeer.getLast_seen() : null;
if (lastSeen == null || effectiveDate.after(lastSeen)) {
autocryptPeerDao.insertOrUpdateLastSeen(packageName, autocryptPeerId, effectiveDate);
}
@ -83,14 +83,14 @@ public class AutocryptInteractor {
}
void updateAutocryptPeerGossipState(String autocryptPeerId, AutocryptPeerUpdate autocryptPeerUpdate) {
AutocryptPeer currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId);
Autocrypt_peers currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId);
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).
// -> 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.
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)) {
return;
}
@ -150,7 +150,7 @@ public class AutocryptInteractor {
public Map<String,AutocryptRecommendationResult> determineAutocryptRecommendations(String... autocryptIds) {
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);
result.put(peerResult.peerId, peerResult);
}
@ -161,58 +161,60 @@ public class AutocryptInteractor {
/** Determines Autocrypt "ui-recommendation", according to spec.
* 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);
if (keyRecommendation != null) return keyRecommendation;
AutocryptRecommendationResult gossipRecommendation = determineAutocryptGossipRecommendation(autocryptKeyStatus);
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
private AutocryptRecommendationResult determineAutocryptKeyRecommendation(AutocryptKeyStatus autocryptKeyStatus) {
AutocryptPeer autocryptPeer = autocryptKeyStatus.autocryptPeer();
Long masterKeyId = autocryptPeer.master_key_id();
private AutocryptRecommendationResult determineAutocryptKeyRecommendation(
SelectAutocryptKeyStatus autocryptKeyStatus) {
Long masterKeyId = autocryptKeyStatus.getMaster_key_id();
boolean hasKey = masterKeyId != null;
boolean isRevoked = autocryptKeyStatus.isKeyRevoked();
boolean isExpired = autocryptKeyStatus.isKeyExpired();
boolean isRevoked = Boolean.TRUE.equals(autocryptKeyStatus.getKey_is_revoked());
boolean isExpired = autocryptKeyStatus.getKey_is_expired_int() != 0;
if (!hasKey || isRevoked || isExpired) {
return null;
}
Date lastSeen = autocryptPeer.last_seen();
Date lastSeenKey = autocryptPeer.last_seen_key();
boolean isVerified = autocryptKeyStatus.isKeyVerified();
Date lastSeen = autocryptKeyStatus.getLast_seen();
Date lastSeenKey = autocryptKeyStatus.getLast_seen_key();
boolean isVerified = autocryptKeyStatus.getKey_is_verified();
boolean isLastSeenOlderThanDiscourageTimespan = lastSeen != null && lastSeenKey != null &&
lastSeenKey.getTime() < (lastSeen.getTime() - AUTOCRYPT_DISCOURAGE_THRESHOLD_MILLIS);
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) {
return new AutocryptRecommendationResult(autocryptPeer.identifier(), AutocryptState.MUTUAL, masterKeyId, isVerified);
return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.MUTUAL, masterKeyId, isVerified);
} else {
return new AutocryptRecommendationResult(autocryptPeer.identifier(), AutocryptState.AVAILABLE, masterKeyId, isVerified);
return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.AVAILABLE, masterKeyId, isVerified);
}
}
@Nullable
private AutocryptRecommendationResult determineAutocryptGossipRecommendation(AutocryptKeyStatus autocryptKeyStatus) {
boolean gossipHasKey = autocryptKeyStatus.hasGossipKey();
boolean gossipIsRevoked = autocryptKeyStatus.isGossipKeyRevoked();
boolean gossipIsExpired = autocryptKeyStatus.isGossipKeyExpired();
boolean isVerified = autocryptKeyStatus.isGossipKeyVerified();
private AutocryptRecommendationResult determineAutocryptGossipRecommendation(
SelectAutocryptKeyStatus autocryptKeyStatus) {
boolean gossipHasKey = autocryptKeyStatus.getGossip_master_key_id() != null;
boolean gossipIsRevoked =
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) {
return null;
}
Long masterKeyId = autocryptKeyStatus.autocryptPeer().gossip_master_key_id();
return new AutocryptRecommendationResult(autocryptKeyStatus.autocryptPeer().identifier(), AutocryptState.DISCOURAGED_GOSSIP, masterKeyId, isVerified);
Long masterKeyId = autocryptKeyStatus.getGossip_master_key_id();
return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.DISCOURAGED_GOSSIP, masterKeyId, isVerified);
}
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.MatrixCursor;
import android.net.Uri;
import androidx.annotation.NonNull;
import android.widget.Toast;
import androidx.annotation.NonNull;
import org.sufficientlysecure.keychain.BuildConfig;
import org.sufficientlysecure.keychain.UidStatus;
import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
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.provider.KeychainExternalContract;
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_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;
}
@ -84,8 +86,9 @@ public class KeychainExternalProvider extends ContentProvider {
}
@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
String[] selectionArgs,
String sortOrder) {
Timber.v("query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")");
Context context = getContext();
if (context == null) {
@ -97,7 +100,8 @@ public class KeychainExternalProvider extends ContentProvider {
int match = uriMatcher.match(uri);
switch (match) {
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);
}
@ -107,12 +111,14 @@ public class KeychainExternalProvider extends ContentProvider {
}
// override package name to use any external
callingPackageName = uri.getLastPathSegment();
callingPackageName = uri.getLastPathSegment();
case AUTOCRYPT_STATUS: {
boolean callerIsAllowed = (match == AUTOCRYPT_STATUS_INTERNAL) || apiPermissionHelper.isAllowedIgnoreErrors();
boolean callerIsAllowed = (match == AUTOCRYPT_STATUS_INTERNAL) ||
apiPermissionHelper.isAllowedIgnoreErrors();
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) {
@ -120,25 +126,32 @@ public class KeychainExternalProvider extends ContentProvider {
}
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) ||
plist.contains(AutocryptStatus.UID_ADDRESS) ||
plist.contains(AutocryptStatus.UID_MASTER_KEY_ID) ||
plist.contains(AutocryptStatus.UID_CANDIDATES);
boolean queriesAutocryptResult = plist.contains(AutocryptStatus.AUTOCRYPT_PEER_STATE) ||
plist.contains(AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID) ||
plist.contains(AutocryptStatus.AUTOCRYPT_KEY_STATUS);
boolean queriesAutocryptResult =
plist.contains(AutocryptStatus.AUTOCRYPT_PEER_STATE) ||
plist.contains(AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID) ||
plist.contains(AutocryptStatus.AUTOCRYPT_KEY_STATUS);
if (isWildcardSelector && queriesAutocryptResult) {
throw new UnsupportedOperationException("Cannot wildcard-query autocrypt results!");
throw new UnsupportedOperationException(
"Cannot wildcard-query autocrypt results!");
}
Map<String, UidStatus> uidStatuses = queriesUidResult ?
loadUidStatusMap(selectionArgs, isWildcardSelector) : Collections.emptyMap();
Map<String, AutocryptRecommendationResult> autocryptStates = queriesAutocryptResult ?
loadAutocryptRecommendationMap(selectionArgs, callingPackageName) : Collections.emptyMap();
loadUidStatusMap(selectionArgs, isWildcardSelector) :
Collections.emptyMap();
Map<String, AutocryptRecommendationResult> autocryptStates =
queriesAutocryptResult ?
loadAutocryptRecommendationMap(selectionArgs, callingPackageName) :
Collections.emptyMap();
MatrixCursor cursor =
mapResultsToProjectedMatrixCursor(projection, selectionArgs, uidStatuses, autocryptStates);
mapResultsToProjectedMatrixCursor(projection, selectionArgs, uidStatuses,
autocryptStates);
uri = DatabaseNotifyManager.getNotifyUriAllKeys();
cursor.setNotificationUri(context.getContentResolver(), uri);
@ -153,8 +166,10 @@ public class KeychainExternalProvider extends ContentProvider {
}
@NonNull
private MatrixCursor mapResultsToProjectedMatrixCursor(String[] projection, String[] selectionArgs,
Map<String, UidStatus> uidStatuses, Map<String, AutocryptRecommendationResult> autocryptStates) {
private MatrixCursor mapResultsToProjectedMatrixCursor(String[] projection,
String[] selectionArgs,
Map<String, UidStatus> uidStatuses,
Map<String, AutocryptRecommendationResult> autocryptStates) {
MatrixCursor cursor = new MatrixCursor(projection);
for (String selectionArg : selectionArgs) {
AutocryptRecommendationResult autocryptResult = autocryptStates.get(selectionArg);
@ -162,7 +177,8 @@ public class KeychainExternalProvider extends ContentProvider {
Object[] row = new Object[projection.length];
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;
} else {
row[i] = columnNameToRowContent(projection[i], autocryptResult, uidStatus);
@ -180,7 +196,8 @@ public class KeychainExternalProvider extends ContentProvider {
if (uidStatus == 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_UNVERIFIED;
}
@ -188,19 +205,19 @@ public class KeychainExternalProvider extends ContentProvider {
if (uidStatus == null) {
return null;
}
return uidStatus.user_id();
return uidStatus.getUser_id();
case AutocryptStatus.UID_MASTER_KEY_ID:
if (uidStatus == null) {
return null;
}
return uidStatus.master_key_id();
return uidStatus.getMaster_key_id();
case AutocryptStatus.UID_CANDIDATES:
if (uidStatus == null) {
return null;
}
return uidStatus.candidates();
return uidStatus.getCandidates();
case AutocryptStatus.AUTOCRYPT_PEER_STATE:
if (autocryptResult == null) {
@ -213,7 +230,8 @@ public class KeychainExternalProvider extends ContentProvider {
return null;
}
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:
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());
if (isWildcardSelector) {
UidStatus uidStatus = userIdDao.getUidStatusByEmailLike(selectionArgs[0]);
org.sufficientlysecure.keychain.UidStatus uidStatus =
userIdDao.getUidStatusByEmailLike(selectionArgs[0]);
return Collections.singletonMap(selectionArgs[0], uidStatus);
} else {
return userIdDao.getUidStatusByEmail(selectionArgs);
@ -238,17 +258,23 @@ public class KeychainExternalProvider extends ContentProvider {
private Map<String, AutocryptRecommendationResult> loadAutocryptRecommendationMap(
String[] selectionArgs, String callingPackageName) {
AutocryptInteractor autocryptInteractor = AutocryptInteractor.getInstance(getContext(), callingPackageName);
AutocryptInteractor autocryptInteractor =
AutocryptInteractor.getInstance(getContext(), callingPackageName);
return autocryptInteractor.determineAutocryptRecommendations(selectionArgs);
}
private int getPeerStateValue(AutocryptState autocryptState) {
switch (autocryptState) {
case DISABLE: return AutocryptStatus.AUTOCRYPT_PEER_DISABLED;
case DISCOURAGED_OLD: return AutocryptStatus.AUTOCRYPT_PEER_DISCOURAGED_OLD;
case DISCOURAGED_GOSSIP: return AutocryptStatus.AUTOCRYPT_PEER_GOSSIP;
case AVAILABLE: return AutocryptStatus.AUTOCRYPT_PEER_AVAILABLE;
case MUTUAL: return AutocryptStatus.AUTOCRYPT_PEER_MUTUAL;
case DISABLE:
return AutocryptStatus.AUTOCRYPT_PEER_DISABLED;
case DISCOURAGED_OLD:
return AutocryptStatus.AUTOCRYPT_PEER_DISCOURAGED_OLD;
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!");
}
@ -269,7 +295,8 @@ public class KeychainExternalProvider extends ContentProvider {
}
@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();
}

View File

@ -57,7 +57,7 @@ import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
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.results.DecryptVerifyResult;
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.KeyRepository;
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.pgp.CanonicalizedPublicKey;
import org.sufficientlysecure.keychain.pgp.SshPublicKey;

View File

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

View File

@ -27,7 +27,7 @@ import android.os.Bundle;
import androidx.recyclerview.widget.LinearLayoutManager;
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.KeyRepository;
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.graphics.drawable.Drawable;
import org.sufficientlysecure.keychain.Api_apps;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.ApiApp;
import org.sufficientlysecure.keychain.daos.ApiAppDao;
import timber.log.Timber;
@ -39,7 +39,7 @@ class RemoteRegisterPresenter {
private RemoteRegisterView view;
private Intent resultData;
private ApiApp apiApp;
private Api_apps apiApp;
RemoteRegisterPresenter(Context context) {
@ -54,7 +54,7 @@ class RemoteRegisterPresenter {
}
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;
try {

View File

@ -26,7 +26,7 @@ import android.graphics.drawable.Drawable;
import androidx.annotation.Nullable;
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.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.daos.ApiAppDao;

View File

@ -31,7 +31,7 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
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.ui.adapter.KeyChoiceAdapter;
import org.sufficientlysecure.keychain.ui.base.RecyclerFragment;

View File

@ -21,24 +21,23 @@ package org.sufficientlysecure.keychain.remote.ui;
import java.util.List;
import android.app.Activity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.os.Bundle;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
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.OpenPgpUtils;
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.KeyRepository;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity;
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;
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);
LiveData<List<UnifiedKeyInfo>> liveData = viewModel.getGenericLiveData(
requireContext(), keyRepository::getAllUnifiedKeyInfoWithSecret);
liveData.observe(this, this::onLoadUnifiedKeyData);
liveData.observe(getViewLifecycleOwner(), this::onLoadUnifiedKeyData);
}
public void onLoadUnifiedKeyData(List<UnifiedKeyInfo> data) {
@ -155,8 +154,7 @@ public class SelectSignKeyIdListFragment extends RecyclerFragment<KeyChoiceAdapt
}
private void onSelectKeyItemClicked(UnifiedKeyInfo keyInfo) {
ApiApp apiApp = ApiApp.create(packageName, packageSignature);
apiAppDao.insertApiApp(apiApp);
apiAppDao.insertApiApp(packageName, packageSignature);
apiAppDao.addAllowedKeyIdForApp(packageName, 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 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.ui.util.KeyInfoFormatter;

View File

@ -46,7 +46,7 @@ import android.widget.Toast;
import com.mikepenz.materialdrawer.util.KeyboardUtil;
import org.sufficientlysecure.keychain.R;
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.remote.ui.RemoteSecurityTokenOperationActivity;
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 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.ui.dialog.RemoteDeduplicateActivity.DeduplicateViewModel;
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;

View File

@ -23,9 +23,6 @@ import java.util.List;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProviders;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -33,26 +30,29 @@ import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
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.LayoutInflater;
import android.view.View;
import android.widget.Button;
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 org.openintents.ssh.authentication.SshAuthenticationApi;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.ApiAppDao;
import org.sufficientlysecure.keychain.daos.KeyRepository;
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.dialog.RemoteSelectAuthenticationKeyPresenter.RemoteSelectAuthenticationKeyView;
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.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 timber.log.Timber;

View File

@ -61,7 +61,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
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.remote.ui.dialog.RemoteSelectIdentityKeyPresenter.RemoteSelectIdentityKeyView;
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.UserId;
import org.sufficientlysecure.keychain.Api_apps;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.model.ApiApp;
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.PgpEditKeyResult;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
@ -59,7 +59,7 @@ class RemoteSelectIdentityKeyPresenter {
private Long selectedMasterKeyId;
private byte[] generatedKeyData;
private ApiAppDao apiAppDao;
private ApiApp apiApp;
private Api_apps apiApp;
RemoteSelectIdentityKeyPresenter(Context context, LifecycleOwner lifecycleOwner) {
@ -98,7 +98,7 @@ class RemoteSelectIdentityKeyPresenter {
Drawable appIcon = packageManager.getApplicationIcon(applicationInfo);
CharSequence appLabel = packageManager.getApplicationLabel(applicationInfo);
apiApp = ApiApp.create(packageName, packageSignature);
apiApp = new Api_apps(0L, packageName, packageSignature);
view.setTitleClientIconAndName(appIcon, appLabel);
}
@ -217,14 +217,14 @@ class RemoteSelectIdentityKeyPresenter {
void onHighlightFinished() {
apiAppDao.insertApiApp(apiApp);
apiAppDao.addAllowedKeyIdForApp(apiApp.package_name(), Objects.requireNonNull(selectedMasterKeyId));
apiAppDao.addAllowedKeyIdForApp(apiApp.getPackage_name(), Objects.requireNonNull(selectedMasterKeyId));
view.finishAndReturn(selectedMasterKeyId);
}
void onImportOpSuccess(ImportKeyResult result) {
long importedMasterKeyId = result.getImportedMasterKeyIds()[0];
apiAppDao.insertApiApp(apiApp);
apiAppDao.addAllowedKeyIdForApp(apiApp.package_name(), importedMasterKeyId);
apiAppDao.addAllowedKeyIdForApp(apiApp.getPackage_name(), importedMasterKeyId);
view.finishAndReturn(importedMasterKeyId);
}

View File

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

View File

@ -30,7 +30,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
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.util.KeyFormattingUtils;

View File

@ -37,7 +37,7 @@ import android.widget.ImageView;
import org.sufficientlysecure.keychain.Constants;
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.OperationResult;
import org.sufficientlysecure.keychain.daos.KeyRepository;

View File

@ -26,8 +26,6 @@ import java.util.regex.Pattern;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -38,18 +36,20 @@ import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import org.bouncycastle.bcpg.sig.KeyFlags;
import org.openintents.openpgp.util.OpenPgpUtils;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Keys;
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.model.SubKey;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.UploadResult;
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.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
@ -420,9 +420,9 @@ public class CreateKeyFinalFragment extends Fragment {
return;
}
List<SubKey> subKeys = keyRepository.getSubKeysByMasterKeyId(saveKeyResult.mMasterKeyId);
for (SubKey subKey : subKeys) {
builder.addOrReplaceSubkeyChange(SubkeyChange.createMoveToSecurityTokenChange(subKey.key_id()));
List<Keys> subKeys = keyRepository.getSubKeysByMasterKeyId(saveKeyResult.mMasterKeyId);
for (Keys subKey : subKeys) {
builder.addOrReplaceSubkeyChange(SubkeyChange.createMoveToSecurityTokenChange(subKey.getKey_id()));
}
// 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.ParcelableKeyRing;
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.ImportKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;

View File

@ -37,7 +37,7 @@ import android.widget.Spinner;
import android.widget.TextView;
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.OperationResult;
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.daos.KeyRepository;
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.EncryptRecipientChip;
import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
@ -121,8 +121,8 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
super.onActivityCreated(savedInstanceState);
EncryptModeViewModel viewModel = ViewModelProviders.of(this).get(EncryptModeViewModel.class);
viewModel.getSignKeyLiveData(requireContext()).observe(this, mSignKeySpinner::setData);
viewModel.getEncryptRecipientLiveData(requireContext()).observe(this, mEncryptKeyView::setData);
viewModel.getSignKeyLiveData(requireContext()).observe(getViewLifecycleOwner(), mSignKeySpinner::setData);
viewModel.getEncryptRecipientLiveData(requireContext()).observe(getViewLifecycleOwner(), mEncryptKeyView::setData);
// preselect keys given, from state or arguments
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.KeyRepository;
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.results.BenchmarkResult;
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);
LiveData<List<FlexibleKeyItem>> liveData = viewModel.getGenericLiveData(requireContext(), this::loadFlexibleKeyItems);
liveData.observe(this, this::onLoadKeyItems);
liveData.observe(getViewLifecycleOwner(), this::onLoadKeyItems);
}
@WorkerThread

View File

@ -21,23 +21,23 @@ package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList;
import java.util.List;
import androidx.lifecycle.LiveData;
import android.database.MatrixCursor;
import android.os.Bundle;
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.View;
import android.view.ViewGroup;
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.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
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.ui.adapter.MultiUserIdsAdapter;
import timber.log.Timber;
@ -85,7 +85,7 @@ public class MultiUserIdsFragment extends Fragment {
KeyRepository keyRepository = KeyRepository.create(activity);
LiveData<List<UserId>> userIdLiveData =
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.sufficientlysecure.keychain.Constants;
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.SecretKeyType;
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.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.keyview.UnifiedKeyInfoViewModel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;

View File

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

View File

@ -42,16 +42,15 @@ import androidx.lifecycle.ViewModelProviders;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
import com.astuetz.PagerSlidingTabStrip;
import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.SubKey;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.UserId;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@ -112,7 +111,7 @@ public class ViewKeyAdvActivity extends BaseActivity implements OnPageChangeList
public static class ViewKeyAdvViewModel extends ViewModel {
private Long masterKeyId;
private LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData;
private LiveData<List<SubKey>> subKeyLiveData;
private LiveData<List<Keys>> subKeyLiveData;
private LiveData<List<UserId>> userIdsLiveData;
void setMasterKeyId(long masterKeyId) {
@ -134,7 +133,7 @@ public class ViewKeyAdvActivity extends BaseActivity implements OnPageChangeList
return unifiedKeyInfoLiveData;
}
LiveData<List<SubKey>> getSubkeyLiveData(Context context) {
LiveData<List<Keys>> getSubkeyLiveData(Context context) {
if (subKeyLiveData == null) {
KeyRepository keyRepository = KeyRepository.create(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.R;
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.util.KeyFormattingUtils;
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.List;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
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.LayoutInflater;
import android.view.Menu;
@ -41,13 +34,20 @@ import android.view.View;
import android.view.ViewGroup;
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.OnItemClickListener;
import eu.davidea.flexibleadapter.items.IFlexible;
import org.sufficientlysecure.keychain.Keys;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.model.SubKey;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
@ -99,8 +99,8 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
subkeysList.setAdapter(subkeysAdapter);
ViewKeyAdvViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyAdvViewModel.class);
viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(this, this::onLoadUnifiedKeyId);
viewModel.getSubkeyLiveData(requireContext()).observe(this, this::onLoadSubKeys);
viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(getViewLifecycleOwner(), this::onLoadUnifiedKeyId);
viewModel.getSubkeyLiveData(requireContext()).observe(getViewLifecycleOwner(), this::onLoadSubKeys);
subkeyEditViewModel = ViewModelProviders.of(this).get(SubkeyEditViewModel.class);
}
@ -114,9 +114,9 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
subkeyEditViewModel.unifiedKeyInfo = unifiedKeyInfo;
}
private void onLoadSubKeys(List<SubKey> subKeys) {
private void onLoadSubKeys(List<Keys> subKeys) {
ArrayList<IFlexible> subKeyItems = new ArrayList<>(subKeys.size());
for (SubKey subKey : subKeys) {
for (Keys subKey : subKeys) {
subKeyItems.add(new SubKeyItem(subKey, subkeyEditViewModel));
}
subkeysAdapter.updateDataSet(subKeyItems);
@ -207,7 +207,7 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
}
private void editSubkey(int position, SubKeyItem item) {
if (subkeyEditViewModel.skpBuilder.hasModificationsForSubkey(item.subkeyInfo.key_id())) {
if (subkeyEditViewModel.skpBuilder.hasModificationsForSubkey(item.subkeyInfo.getKey_id())) {
return;
}
@ -219,8 +219,8 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
editSubkeyExpiry(item);
break;
case EditSubkeyDialogFragment.MESSAGE_REVOKE:
SubKey subKey = item.subkeyInfo;
subkeyEditViewModel.skpBuilder.addRevokeSubkey(subKey.key_id());
Keys subKey = item.subkeyInfo;
subkeyEditViewModel.skpBuilder.addRevokeSubkey(subKey.getKey_id());
break;
case EditSubkeyDialogFragment.MESSAGE_STRIP: {
editSubkeyToggleStrip(item);
@ -241,21 +241,21 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
}
private void editSubkeyToggleStrip(SubKeyItem item) {
SubKey subKey = item.subkeyInfo;
if (subKey.has_secret() == SecretKeyType.GNU_DUMMY) {
Keys subKey = item.subkeyInfo;
if (subKey.getHas_secret() == SecretKeyType.GNU_DUMMY) {
// Key is already stripped; this is a no-op.
return;
}
subkeyEditViewModel.skpBuilder.addOrReplaceSubkeyChange(SubkeyChange.createStripChange(subKey.key_id()));
subkeyEditViewModel.skpBuilder.addOrReplaceSubkeyChange(SubkeyChange.createStripChange(subKey.getKey_id()));
}
private void editSubkeyExpiry(SubKeyItem item) {
SubKey subKey = item.subkeyInfo;
Keys subKey = item.subkeyInfo;
final long keyId = subKey.key_id();
final Long creationDate = subKey.creation();
final Long expiryDate = subKey.expiry();
final long keyId = subKey.getKey_id();
final Long creationDate = subKey.getCreation();
final Long expiryDate = subKey.getExpiry();
Handler returnHandler = new Handler() {
@Override

View File

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

View File

@ -14,7 +14,7 @@ import eu.davidea.flexibleadapter.items.IFlexible;
import eu.davidea.viewholders.FlexibleViewHolder;
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.FlexibleKeyItem.FlexibleSectionableKeyItem;
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;

View File

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

View File

@ -32,9 +32,6 @@ import android.view.View;
import android.view.View.OnClickListener;
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.daos.KeyRepository;
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.ImportKeysOperationCallback;
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.results.ImportKeyResult;
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.viewholders.FlexibleViewHolder;
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.util.KeyInfoFormatter;

View File

@ -33,7 +33,7 @@ import android.widget.TextView;
import android.widget.ViewAnimator;
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.service.SaveKeyringParcel;
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.ViewGroup;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.materialchips.ChipView;
import org.sufficientlysecure.materialchips.ChipsInput;
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.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey;
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipAdapter.ItemViewHolder;
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 email;
if (keyInfo.name() == null) {

View File

@ -10,7 +10,7 @@ import android.util.AttributeSet;
import org.sufficientlysecure.materialchips.ChipsInput;
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;

View File

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

View File

@ -1,15 +1,15 @@
package org.sufficientlysecure.keychain.ui.keyview;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import android.content.Context;
import android.net.Uri;
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
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.keyimport.HkpKeyserverAddress;
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.ImportKeyResult;
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.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProvider;
import org.sufficientlysecure.keychain.Key_metadata;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
import org.sufficientlysecure.keychain.model.KeyMetadata;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
@ -265,16 +265,16 @@ public class ViewKeyFragment extends Fragment implements OnMenuItemClickListener
identitiesAdapter.setData(identityInfos);
}
private void onLoadKeyMetadata(KeyMetadata keyMetadata) {
private void onLoadKeyMetadata(Key_metadata keyMetadata) {
if (keyMetadata == null) {
keyserverStatusView.setDisplayStatusUnknown();
} else if (keyMetadata.hasBeenUpdated()) {
if (keyMetadata.isPublished()) {
} else if (keyMetadata.getLast_updated() != null) {
if (keyMetadata.getSeen_on_keyservers() != null && keyMetadata.getSeen_on_keyservers()) {
keyserverStatusView.setDisplayStatusPublished();
} else {
keyserverStatusView.setDisplayStatusNotPublished();
}
keyserverStatusView.setLastUpdated(keyMetadata.last_updated());
keyserverStatusView.setLastUpdated(keyMetadata.getLast_updated());
} else {
keyserverStatusView.setDisplayStatusUnknown();
}

View File

@ -22,47 +22,43 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import androidx.sqlite.db.SupportSQLiteDatabase;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import androidx.annotation.Nullable;
import androidx.annotation.Nullable;
import com.google.auto.value.AutoValue;
import com.squareup.sqldelight.SqlDelightQuery;
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.model.AutocryptPeer;
import org.sufficientlysecure.keychain.model.UserPacket;
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
import org.sufficientlysecure.keychain.daos.UserIdDao;
import org.sufficientlysecure.keychain.model.UserId;
import org.sufficientlysecure.keychain.ui.util.PackageIconGetter;
public class IdentityDao {
private final SupportSQLiteDatabase db;
private final PackageIconGetter packageIconGetter;
private final PackageManager packageManager;
private final AutocryptPeerDao autocryptPeerDao;
private final UserIdDao userIdDao;
public static IdentityDao getInstance(Context context) {
SupportSQLiteDatabase db = KeychainDatabase.getInstance(context).getWritableDatabase();
PackageManager packageManager = context.getPackageManager();
PackageIconGetter iconGetter = PackageIconGetter.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,
PackageManager packageManager, PackageIconGetter iconGetter,
AutocryptPeerDao autocryptPeerDao) {
this.db = db;
private IdentityDao(PackageManager packageManager,
PackageIconGetter iconGetter, AutocryptPeerDao autocryptPeerDao,
UserIdDao userIdDao) {
this.packageManager = packageManager;
this.packageIconGetter = iconGetter;
this.autocryptPeerDao = autocryptPeerDao;
this.userIdDao = userIdDao;
}
public List<IdentityInfo> getIdentityInfos(long masterKeyId) {
@ -74,29 +70,36 @@ public class IdentityDao {
return Collections.unmodifiableList(identities);
}
private void correlateOrAddAutocryptPeers(ArrayList<IdentityInfo> identities, long masterKeyId) {
for (AutocryptPeer autocryptPeer : autocryptPeerDao.getAutocryptPeersForKey(masterKeyId)) {
String packageName = autocryptPeer.package_name();
String autocryptId = autocryptPeer.identifier();
private void correlateOrAddAutocryptPeers(ArrayList<IdentityInfo> identities,
long masterKeyId) {
for (Autocrypt_peers autocryptPeer : autocryptPeerDao.getAutocryptPeersForKey(
masterKeyId)) {
String packageName = autocryptPeer.getPackage_name();
String autocryptId = autocryptPeer.getIdentifier();
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) {
int position = identities.indexOf(associatedUserIdInfo);
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
.create(masterKeyId, associatedUserIdInfo, autocryptId, packageName, drawable, autocryptPeerIntent);
.create(masterKeyId, associatedUserIdInfo, autocryptId, packageName,
drawable, autocryptPeerIntent);
identities.set(position, autocryptPeerInfo);
} else {
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
.create(masterKeyId, autocryptId, packageName, drawable, autocryptPeerIntent);
.create(masterKeyId, autocryptId, packageName, drawable,
autocryptPeerIntent);
identities.add(autocryptPeerInfo);
}
}
}
private Intent getAutocryptPeerActivityIntentIfResolvable(String packageName, String autocryptPeer) {
private Intent getAutocryptPeerActivityIntentIfResolvable(String packageName,
String autocryptPeer) {
Intent intent = new Intent();
intent.setAction("org.autocrypt.PEER_ACTION");
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) {
if (identityInfo instanceof UserIdInfo) {
UserIdInfo userIdInfo = (UserIdInfo) identityInfo;
@ -123,72 +127,90 @@ public class IdentityDao {
return null;
}
private void loadUserIds(ArrayList<IdentityInfo> identities, long... masterKeyId) {
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyId);
try (Cursor cursor = db.query(query)) {
while (cursor.moveToNext()) {
UserId userId = UserPacket.USER_ID_MAPPER.map(cursor);
if (userId.name() != null || userId.email() != null) {
IdentityInfo identityInfo = UserIdInfo.create(
userId.master_key_id(), userId.rank(), userId.isVerified(), userId.is_primary(), userId.name(), userId.email(), userId.comment());
identities.add(identityInfo);
}
private void loadUserIds(ArrayList<IdentityInfo> identities, long... masterKeyIds) {
for (UserId userId : userIdDao.getUserIdsByMasterKeyIds(masterKeyIds)) {
if (userId.name() != null || userId.email() != null) {
IdentityInfo identityInfo = UserIdInfo.create(
userId.master_key_id(), userId.rank(), userId.isVerified(),
userId.is_primary(), userId.name(), userId.email(), userId.email());
identities.add(identityInfo);
}
}
}
public interface IdentityInfo {
long getMasterKeyId();
int getRank();
boolean isVerified();
boolean isPrimary();
}
@AutoValue
public abstract static class UserIdInfo implements IdentityInfo {
public abstract long getMasterKeyId();
public abstract int getRank();
public abstract boolean isVerified();
public abstract boolean isPrimary();
@Nullable
public abstract String getName();
@Nullable
public abstract String getEmail();
@Nullable
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) {
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
public abstract static class AutocryptPeerInfo implements IdentityInfo {
public abstract long getMasterKeyId();
public abstract int getRank();
public abstract boolean isVerified();
public abstract boolean isPrimary();
public abstract String getIdentity();
public abstract String getPackageName();
@Nullable
public abstract Drawable getAppIcon();
@Nullable
public abstract UserIdInfo getUserIdInfo();
@Nullable
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) {
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId, userIdInfo.getRank(), userIdInfo.isVerified(),
userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo, autocryptPeerIntent);
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId, userIdInfo.getRank(),
userIdInfo.isVerified(),
userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo,
autocryptPeerIntent);
}
static AutocryptPeerInfo create(long masterKeyId, String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) {
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId,0, false, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent);
static AutocryptPeerInfo create(long masterKeyId, String autocryptPeer, String packageName,
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 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.PgpSecurityConstants;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
import org.sufficientlysecure.keychain.daos.KeyRepository;
public class SubkeyStatusDao {
@ -51,7 +51,7 @@ public class SubkeyStatusDao {
SubKeyItem keyCertify = null;
ArrayList<SubKeyItem> keysSign = 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);
if (ski.mKeyId == masterKeyId) {
@ -183,23 +183,23 @@ public class SubkeyStatusDao {
final boolean mCanCertify, mCanSign, mCanEncrypt;
public final KeySecurityProblem mSecurityProblem;
SubKeyItem(long masterKeyId, SubKey subKey) {
mKeyId = subKey.key_id();
mCreation = new Date(subKey.creation() * 1000);
SubKeyItem(long masterKeyId, Keys subKey) {
mKeyId = subKey.getKey_id();
mCreation = new Date(subKey.getCreation() * 1000);
mSecretKeyType = subKey.has_secret();
mSecretKeyType = subKey.getHas_secret();
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());
mCanCertify = subKey.can_certify();
mCanSign = subKey.can_sign();
mCanEncrypt = subKey.can_encrypt();
mCanCertify = subKey.getCan_certify();
mCanSign = subKey.getCan_sign();
mCanEncrypt = subKey.getCan_encrypt();
int algorithm = subKey.algorithm();
Integer bitStrength = subKey.key_size();
String curveOid = subKey.key_curve_oid();
int algorithm = subKey.getAlgorithm();
Integer bitStrength = subKey.getKey_size();
String curveOid = subKey.getKey_curve_oid();
mSecurityProblem = PgpSecurityConstants.getKeySecurityProblem(
masterKeyId, mKeyId, algorithm, bitStrength, curveOid);

View File

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

View File

@ -31,7 +31,7 @@ import android.view.View;
import android.widget.AdapterView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
public class KeySpinner extends AppCompatSpinner {
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.daos.KeyRepository;
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.SshPublicKey;
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 (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
key_id INTEGER,
key_id INTEGER NOT NULL,
package_name TEXT NOT NULL,
UNIQUE (key_id, package_name),
FOREIGN KEY (package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE

View File

@ -1,16 +1,16 @@
import java.util.Date;
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
import org.sufficientlysecure.keychain.model.GossipOrigin;
CREATE TABLE IF NOT EXISTS autocrypt_peers (
package_name TEXT NOT NULL,
identifier TEXT NOT NULL,
last_seen INTEGER AS Date NULL,
last_seen_key INTEGER AS Date NULL,
last_seen INTEGER AS Date,
last_seen_key INTEGER AS Date,
is_mutual INTEGER AS Boolean NOT NULL DEFAULT 0,
master_key_id INTEGER NULL,
gossip_master_key_id INTEGER NULL,
gossip_last_seen_key INTEGER AS Date NULL,
gossip_origin INTEGER AS GossipOrigin NULL,
master_key_id INTEGER,
gossip_master_key_id INTEGER,
gossip_last_seen_key INTEGER AS Date,
gossip_origin INTEGER AS GossipOrigin,
PRIMARY KEY(package_name, identifier),
FOREIGN KEY(package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE
);
@ -54,10 +54,10 @@ selectAutocryptKeyStatus:
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 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,
gossip_key.is_revoked AS gossip_key_is_revoked_int,
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.gossip_master_key_id AND verified = 1 ) AS gossip_key_is_verified_int
ac_key.is_revoked AS key_is_revoked,
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,
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
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)

View File

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

View File

@ -16,7 +16,7 @@ SELECT *
deleteAllLastUpdatedTimes:
UPDATE key_metadata
SET last_updated = null, seen_on_keyservers = null;
SET last_updated = NULL, seen_on_keyservers = NULL;
replaceKeyMetadata:
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 (
master_key_id INTEGER NOT NULL PRIMARY KEY,
key_ring_data BLOB NULL
key_ring_data BLOB
);
insertKeyRingPublic:
INSERT INTO keyrings_public (master_key_id, key_ring_data) VALUES (?, ?);
INSERT INTO keyrings_public (master_key_id, key_ring_data) VALUES ?;
selectAllMasterKeyIds:
SELECT master_key_id

View File

@ -6,7 +6,7 @@ CREATE TABLE IF NOT EXISTS key_signatures (
);
insertKeySignature:
INSERT INTO key_signatures (master_key_id, signer_key_id) VALUES (?, ?);
INSERT INTO key_signatures (master_key_id, signer_key_id) VALUES ?;
selectMasterKeyIdsBySigner:
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,
can_certify, can_sign, can_encrypt, can_authenticate,
is_revoked, has_secret, is_secure, creation, expiry, validFrom
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
) VALUES ?;
updateHasSecretByMasterKeyId:
UPDATE keys
@ -56,11 +56,11 @@ SELECT master_key_id, rank, key_id, key_size, key_curve_oid, algorithm, fingerpr
unifiedKeyView:
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_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_int,
(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,
(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,
(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 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
@ -72,7 +72,7 @@ CREATE VIEW unifiedKeyView AS
selectAllUnifiedKeyInfo:
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:
SELECT * FROM unifiedKeyView
@ -89,12 +89,12 @@ SELECT * FROM unifiedKeyView
selectAllUnifiedKeyInfoWithSecret:
SELECT * FROM unifiedKeyView
WHERE has_any_secret_int = 1
WHERE has_any_secret = 1
ORDER BY creation DESC;
selectAllUnifiedKeyInfoWithAuthKeySecret:
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;
selectMasterKeyIdBySubkey:

View File

@ -16,8 +16,7 @@ CREATE TABLE IF NOT EXISTS user_packets(
);
insertUserPacket:
INSERT INTO user_packets (master_key_id, rank, type, user_id, name, email, comment, attribute_data, is_primary, is_revoked)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
INSERT INTO user_packets VALUES ?;
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

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.shadows.ShadowLog;
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.PromoteKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;

View File

@ -27,7 +27,6 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import org.apache.tools.ant.util.StringUtils;
import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.Packet;
import org.bouncycastle.bcpg.PacketTags;
@ -388,9 +387,9 @@ public class PgpEncryptDecryptTest {
Assert.assertTrue("verification must succeed", result.success());
Assert.assertTrue("verification text should equal plaintext (ignoring newlines)",
new String(out.toByteArray()).replace(StringUtils.LINE_SEP, "")
.equals(plaintext.replace("\r", "").replace("\n", "")));
Assert.assertEquals("verification text should equal plaintext (ignoring newlines)",
out.toString().replace("\r", "").replace("\n", ""),
plaintext.replace("\r", "").replace("\n", ""));
Assert.assertEquals("decryptionResult should be RESULT_NOT_ENCRYPTED",
OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED, result.getDecryptionResult().getResult());
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.sufficientlysecure.keychain.KeychainTestRunner;
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.SaveKeyringResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
@ -128,7 +128,6 @@ public class KeyRepositorySaveTest {
CanonicalizedPublicKeyRing pubRing = mDatabaseInteractor.getCanonicalizedPublicKeyRing(keyId);
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",
0, (long) pubRing.getPublicKey().getKeyUsage());

View File

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

View File

@ -1,4 +1,8 @@
buildscript {
ext {
kotlin_version = '1.8.20'
}
repositories {
google()
mavenCentral()
@ -6,8 +10,10 @@ buildscript {
dependencies {
// 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.squareup.sqldelight:gradle-plugin:0.8.0'
classpath 'com.android.tools.build:gradle:7.4.2'
// 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'
}
}

2
extern/bouncycastle vendored

@ -1 +1 @@
Subproject commit d920f59594858d2835c330ec95b9dad0c4b7d00c
Subproject commit 187ca21dd44766942e6c85e3a85430ecbca77f22

@ -1 +1 @@
Subproject commit 8bc98b412bd7cd546b33eac1ced1c1cb302906ca
Subproject commit f91db6be300e8a777c49bbcb8ad0b3a9a583ef08

View File

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

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