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:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -37,4 +37,7 @@ fastlane/screenshots
|
|||||||
fastlane/test_output
|
fastlane/test_output
|
||||||
|
|
||||||
# omit for now:
|
# omit for now:
|
||||||
fastlane/Appfile
|
fastlane/Appfile
|
||||||
|
|
||||||
|
OpenKeychain/release
|
||||||
|
OpenKeychain/google
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
apply plugin: 'com.android.application'
|
plugins {
|
||||||
apply plugin: 'com.squareup.sqldelight'
|
id 'com.android.application'
|
||||||
|
id 'kotlin-android'
|
||||||
|
id 'com.squareup.sqldelight'
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// from local Android SDK
|
// from local Android SDK
|
||||||
@@ -20,6 +23,7 @@ dependencies {
|
|||||||
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.9'
|
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.9'
|
||||||
implementation 'org.apache.james:apache-mime4j-core:0.8.1'
|
implementation 'org.apache.james:apache-mime4j-core:0.8.1'
|
||||||
implementation 'org.apache.james:apache-mime4j-dom:0.8.1'
|
implementation 'org.apache.james:apache-mime4j-dom:0.8.1'
|
||||||
|
implementation "com.squareup.sqldelight:android-driver:1.5.4"
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
implementation 'org.sufficientlysecure:html-textview:3.1'
|
implementation 'org.sufficientlysecure:html-textview:3.1'
|
||||||
@@ -86,6 +90,7 @@ dependencies {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||||
|
namespace 'org.sufficientlysecure.keychain'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 15
|
minSdkVersion 15
|
||||||
|
|||||||
@@ -23,17 +23,15 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||||
import androidx.sqlite.db.SupportSQLiteOpenHelper;
|
import androidx.sqlite.db.SupportSQLiteOpenHelper;
|
||||||
import androidx.sqlite.db.SupportSQLiteOpenHelper.Callback;
|
import androidx.sqlite.db.SupportSQLiteOpenHelper.Callback;
|
||||||
import androidx.sqlite.db.SupportSQLiteOpenHelper.Configuration;
|
import androidx.sqlite.db.SupportSQLiteOpenHelper.Configuration;
|
||||||
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory;
|
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory;
|
||||||
import android.content.Context;
|
import com.squareup.sqldelight.android.AndroidSqliteDriver;
|
||||||
import android.database.Cursor;
|
import org.sufficientlysecure.keychain.model.CustomColumnAdapters;
|
||||||
import android.database.SQLException;
|
|
||||||
import android.database.sqlite.SQLiteException;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.daos.LocalSecretKeyStorage;
|
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@@ -41,15 +39,18 @@ import timber.log.Timber;
|
|||||||
/**
|
/**
|
||||||
* SQLite Datatypes (from http://www.sqlite.org/datatype3.html)
|
* SQLite Datatypes (from http://www.sqlite.org/datatype3.html)
|
||||||
* - NULL. The value is a NULL value.
|
* - NULL. The value is a NULL value.
|
||||||
* - INTEGER. The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude of the value.
|
* - INTEGER. The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending on the
|
||||||
|
* magnitude of the value.
|
||||||
* - REAL. The value is a floating point value, stored as an 8-byte IEEE floating point number.
|
* - REAL. The value is a floating point value, stored as an 8-byte IEEE floating point number.
|
||||||
* - TEXT. The value is a text string, stored using the database encoding (UTF-8, UTF-16BE or UTF-16LE).
|
* - TEXT. The value is a text string, stored using the database encoding (UTF-8, UTF-16BE or
|
||||||
|
* UTF-16LE).
|
||||||
* - BLOB. The value is a blob of data, stored exactly as it was input.
|
* - BLOB. The value is a blob of data, stored exactly as it was input.
|
||||||
*/
|
*/
|
||||||
public class KeychainDatabase {
|
public class KeychainDatabase {
|
||||||
private static final String DATABASE_NAME = "openkeychain.db";
|
private static final String DATABASE_NAME = "openkeychain.db";
|
||||||
private static final int DATABASE_VERSION = 34;
|
private static final int DATABASE_VERSION = 35;
|
||||||
private final SupportSQLiteOpenHelper supportSQLiteOpenHelper;
|
private final SupportSQLiteOpenHelper supportSQLiteOpenHelper;
|
||||||
|
private final Database sqldelightDatabase;
|
||||||
|
|
||||||
private static KeychainDatabase sInstance;
|
private static KeychainDatabase sInstance;
|
||||||
|
|
||||||
@@ -71,12 +72,15 @@ public class KeychainDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onUpgrade(SupportSQLiteDatabase db, int oldVersion,
|
||||||
KeychainDatabase.this.onUpgrade(db, context, oldVersion, newVersion);
|
int newVersion) {
|
||||||
|
KeychainDatabase.this.onUpgrade(db, context, oldVersion,
|
||||||
|
newVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDowngrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onDowngrade(SupportSQLiteDatabase db,
|
||||||
|
int oldVersion, int newVersion) {
|
||||||
KeychainDatabase.this.onDowngrade();
|
KeychainDatabase.this.onDowngrade();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,12 +90,19 @@ public class KeychainDatabase {
|
|||||||
if (!db.isReadOnly()) {
|
if (!db.isReadOnly()) {
|
||||||
// Enable foreign key constraints
|
// Enable foreign key constraints
|
||||||
db.execSQL("PRAGMA foreign_keys=ON;");
|
db.execSQL("PRAGMA foreign_keys=ON;");
|
||||||
if (Constants.DEBUG) {
|
|
||||||
recreateUnifiedKeyView(db);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).build());
|
}).build());
|
||||||
|
AndroidSqliteDriver driver = new AndroidSqliteDriver(supportSQLiteOpenHelper);
|
||||||
|
sqldelightDatabase = Database.Companion.invoke(driver,
|
||||||
|
new Autocrypt_peers.Adapter(CustomColumnAdapters.DATE_ADAPTER,
|
||||||
|
CustomColumnAdapters.DATE_ADAPTER,
|
||||||
|
CustomColumnAdapters.DATE_ADAPTER,
|
||||||
|
CustomColumnAdapters.GOSSIP_ORIGIN_ADAPTER),
|
||||||
|
new Certs.Adapter(CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER),
|
||||||
|
new Key_metadata.Adapter(CustomColumnAdapters.DATE_ADAPTER),
|
||||||
|
new Keys.Adapter(CustomColumnAdapters.SECRET_KEY_TYPE_ADAPTER)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SupportSQLiteDatabase getReadableDatabase() {
|
public SupportSQLiteDatabase getReadableDatabase() {
|
||||||
@@ -102,328 +113,85 @@ public class KeychainDatabase {
|
|||||||
return supportSQLiteOpenHelper.getWritableDatabase();
|
return supportSQLiteOpenHelper.getWritableDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Database getSqlDelightDatabase() {
|
||||||
|
return sqldelightDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") // using some sqldelight constants
|
@SuppressWarnings("deprecation") // using some sqldelight constants
|
||||||
private void onCreate(SupportSQLiteDatabase db, Context context) {
|
private void onCreate(SupportSQLiteDatabase db, Context context) {
|
||||||
Timber.w("Creating database...");
|
Timber.w("Creating database...");
|
||||||
|
|
||||||
db.execSQL(KeyRingsPublicModel.CREATE_TABLE);
|
AndroidSqliteDriver sqlDriver = new AndroidSqliteDriver(db);
|
||||||
db.execSQL(KeysModel.CREATE_TABLE);
|
Database.Companion.getSchema().create(sqlDriver);
|
||||||
db.execSQL(UserPacketsModel.CREATE_TABLE);
|
recreateDatabaseViews(db);
|
||||||
db.execSQL(CertsModel.CREATE_TABLE);
|
|
||||||
db.execSQL(KeyMetadataModel.CREATE_TABLE);
|
|
||||||
db.execSQL(KeySignaturesModel.CREATE_TABLE);
|
|
||||||
db.execSQL(ApiAppsModel.CREATE_TABLE);
|
|
||||||
db.execSQL(OverriddenWarningsModel.CREATE_TABLE);
|
|
||||||
db.execSQL(AutocryptPeersModel.CREATE_TABLE);
|
|
||||||
db.execSQL(ApiAllowedKeysModel.CREATE_TABLE);
|
|
||||||
db.execSQL(KeysModel.UNIFIEDKEYVIEW);
|
|
||||||
db.execSQL(KeysModel.VALIDKEYSVIEW);
|
|
||||||
db.execSQL(KeysModel.VALIDMASTERKEYSVIEW);
|
|
||||||
db.execSQL(UserPacketsModel.UIDSTATUS);
|
|
||||||
|
|
||||||
db.execSQL("CREATE INDEX keys_by_rank ON keys (" + KeysModel.RANK + ", " + KeysModel.MASTER_KEY_ID + ");");
|
db.execSQL("CREATE INDEX keys_by_rank ON keys (rank, master_key_id);");
|
||||||
db.execSQL("CREATE INDEX uids_by_rank ON user_packets (" + UserPacketsModel.RANK + ", "
|
db.execSQL("CREATE INDEX uids_by_rank ON user_packets (rank, user_id, master_key_id);");
|
||||||
+ UserPacketsModel.USER_ID + ", " + UserPacketsModel.MASTER_KEY_ID + ");");
|
db.execSQL("CREATE INDEX verified_certs ON certs (verified, master_key_id);");
|
||||||
db.execSQL("CREATE INDEX verified_certs ON certs ("
|
db.execSQL("CREATE INDEX uids_by_email ON user_packets (email);");
|
||||||
+ CertsModel.VERIFIED + ", " + CertsModel.MASTER_KEY_ID + ");");
|
|
||||||
db.execSQL("CREATE INDEX uids_by_email ON user_packets ("
|
|
||||||
+ UserPacketsModel.EMAIL + ");");
|
|
||||||
|
|
||||||
Preferences.getPreferences(context).setKeySignaturesTableInitialized();
|
Preferences.getPreferences(context).setKeySignaturesTableInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onUpgrade(SupportSQLiteDatabase db, Context context, int oldVersion, int newVersion) {
|
private void onUpgrade(SupportSQLiteDatabase db, Context context, int oldVersion,
|
||||||
|
int newVersion) {
|
||||||
Timber.d("Upgrading db from " + oldVersion + " to " + newVersion);
|
Timber.d("Upgrading db from " + oldVersion + " to " + newVersion);
|
||||||
|
if (oldVersion < 34) {
|
||||||
|
throw new IllegalStateException("upgrades from older versions not supported");
|
||||||
|
}
|
||||||
switch (oldVersion) {
|
switch (oldVersion) {
|
||||||
case 1:
|
case 34:
|
||||||
// add has_secret for all who are upgrading from a beta version
|
// nothing
|
||||||
try {
|
|
||||||
db.execSQL("ALTER TABLE keys ADD COLUMN has_secret INTEGER");
|
|
||||||
} catch (Exception e) {
|
|
||||||
// never mind, the column probably already existed
|
|
||||||
}
|
|
||||||
// fall through
|
|
||||||
case 2:
|
|
||||||
// ECC support
|
|
||||||
try {
|
|
||||||
db.execSQL("ALTER TABLE keys ADD COLUMN key_curve_oid TEXT");
|
|
||||||
} catch (Exception e) {
|
|
||||||
// never mind, the column probably already existed
|
|
||||||
}
|
|
||||||
// fall through
|
|
||||||
case 3:
|
|
||||||
// better s2k detection, we need consolidate
|
|
||||||
// fall through
|
|
||||||
case 4:
|
|
||||||
try {
|
|
||||||
db.execSQL("ALTER TABLE keys ADD COLUMN can_authenticate INTEGER");
|
|
||||||
} catch (Exception e) {
|
|
||||||
// never mind, the column probably already existed
|
|
||||||
}
|
|
||||||
// fall through
|
|
||||||
case 5:
|
|
||||||
// do consolidate for 3.0 beta3
|
|
||||||
// fall through
|
|
||||||
case 6:
|
|
||||||
db.execSQL("ALTER TABLE user_ids ADD COLUMN type INTEGER");
|
|
||||||
db.execSQL("ALTER TABLE user_ids ADD COLUMN attribute_data BLOB");
|
|
||||||
case 7:
|
|
||||||
// new table for allowed key ids in API
|
|
||||||
try {
|
|
||||||
db.execSQL(ApiAppsModel.CREATE_TABLE);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// never mind, the column probably already existed
|
|
||||||
}
|
|
||||||
case 8:
|
|
||||||
// tbale name for user_ids changed to user_packets
|
|
||||||
db.execSQL("DROP TABLE IF EXISTS certs");
|
|
||||||
db.execSQL("DROP TABLE IF EXISTS user_ids");
|
|
||||||
db.execSQL("CREATE TABLE IF NOT EXISTS user_packets("
|
|
||||||
+ "master_key_id INTEGER, "
|
|
||||||
+ "type INT, "
|
|
||||||
+ "user_id TEXT, "
|
|
||||||
+ "attribute_data BLOB, "
|
|
||||||
|
|
||||||
+ "is_primary INTEGER, "
|
|
||||||
+ "is_revoked INTEGER, "
|
|
||||||
+ "rank INTEGER, "
|
|
||||||
|
|
||||||
+ "PRIMARY KEY(master_key_id, rank), "
|
|
||||||
+ "FOREIGN KEY(master_key_id) REFERENCES "
|
|
||||||
+ "keyrings_public(master_key_id) ON DELETE CASCADE"
|
|
||||||
+ ")");
|
|
||||||
db.execSQL("CREATE TABLE IF NOT EXISTS certs("
|
|
||||||
+ "master_key_id INTEGER,"
|
|
||||||
+ "rank INTEGER, " // rank of certified uid
|
|
||||||
|
|
||||||
+ "key_id_certifier INTEGER, " // certifying key
|
|
||||||
+ "type INTEGER, "
|
|
||||||
+ "verified INTEGER, "
|
|
||||||
+ "creation INTEGER, "
|
|
||||||
|
|
||||||
+ "data BLOB, "
|
|
||||||
|
|
||||||
+ "PRIMARY KEY(master_key_id, rank, "
|
|
||||||
+ "key_id_certifier), "
|
|
||||||
+ "FOREIGN KEY(master_key_id) REFERENCES "
|
|
||||||
+ "keyrings_public(master_key_id) ON DELETE CASCADE,"
|
|
||||||
+ "FOREIGN KEY(master_key_id, rank) REFERENCES "
|
|
||||||
+ "user_packets(master_key_id, rank) ON DELETE CASCADE"
|
|
||||||
+ ")");
|
|
||||||
case 9:
|
|
||||||
// do nothing here, just consolidate
|
|
||||||
case 10:
|
|
||||||
// fix problems in database, see #1402 for details
|
|
||||||
// https://github.com/open-keychain/open-keychain/issues/1402
|
|
||||||
// no longer needed, api_accounts is deprecated
|
|
||||||
// db.execSQL("DELETE FROM api_accounts WHERE key_id BETWEEN 0 AND 3");
|
|
||||||
case 11:
|
|
||||||
db.execSQL("CREATE TABLE IF NOT EXISTS updated_keys ("
|
|
||||||
+ "master_key_id INTEGER PRIMARY KEY, "
|
|
||||||
+ "last_updated INTEGER, "
|
|
||||||
+ "FOREIGN KEY(master_key_id) REFERENCES "
|
|
||||||
+ "keyrings_public(master_key_id) ON DELETE CASCADE"
|
|
||||||
+ ")");
|
|
||||||
case 12:
|
|
||||||
// do nothing here, just consolidate
|
|
||||||
case 13:
|
|
||||||
db.execSQL("CREATE INDEX keys_by_rank ON keys (rank);");
|
|
||||||
db.execSQL("CREATE INDEX uids_by_rank ON user_packets (rank, user_id, master_key_id);");
|
|
||||||
db.execSQL("CREATE INDEX verified_certs ON certs (verified, master_key_id);");
|
|
||||||
case 14:
|
|
||||||
db.execSQL("ALTER TABLE user_packets ADD COLUMN name TEXT");
|
|
||||||
db.execSQL("ALTER TABLE user_packets ADD COLUMN email TEXT");
|
|
||||||
db.execSQL("ALTER TABLE user_packets ADD COLUMN comment TEXT");
|
|
||||||
case 15:
|
|
||||||
db.execSQL("CREATE INDEX uids_by_name ON user_packets (name COLLATE NOCASE)");
|
|
||||||
db.execSQL("CREATE INDEX uids_by_email ON user_packets (email COLLATE NOCASE)");
|
|
||||||
case 16:
|
|
||||||
// splitUserId changed: Execute consolidate for new parsing of name, email
|
|
||||||
case 17:
|
|
||||||
// splitUserId changed: Execute consolidate for new parsing of name, email
|
|
||||||
case 18:
|
|
||||||
db.execSQL("ALTER TABLE keys ADD COLUMN is_secure INTEGER");
|
|
||||||
case 19:
|
|
||||||
// emergency fix for crashing consolidate
|
|
||||||
db.execSQL("UPDATE keys SET is_secure = 1;");
|
|
||||||
case 20:
|
|
||||||
db.execSQL(
|
|
||||||
"CREATE TABLE IF NOT EXISTS overridden_warnings ("
|
|
||||||
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
|
||||||
+ "identifier TEXT NOT NULL UNIQUE "
|
|
||||||
+ ")");
|
|
||||||
|
|
||||||
case 21:
|
|
||||||
try {
|
|
||||||
db.execSQL("ALTER TABLE updated_keys ADD COLUMN seen_on_keyservers INTEGER;");
|
|
||||||
} catch (SQLiteException e) {
|
|
||||||
// don't bother, the column probably already existed
|
|
||||||
}
|
|
||||||
|
|
||||||
case 22:
|
|
||||||
db.execSQL("CREATE TABLE IF NOT EXISTS api_autocrypt_peers ("
|
|
||||||
+ "package_name TEXT NOT NULL, "
|
|
||||||
+ "identifier TEXT NOT NULL, "
|
|
||||||
+ "last_updated INTEGER NOT NULL, "
|
|
||||||
+ "last_seen_key INTEGER NOT NULL, "
|
|
||||||
+ "state INTEGER NOT NULL, "
|
|
||||||
+ "master_key_id INTEGER, "
|
|
||||||
+ "PRIMARY KEY(package_name, identifier), "
|
|
||||||
+ "FOREIGN KEY(package_name) REFERENCES api_apps(package_name) ON DELETE CASCADE"
|
|
||||||
+ ")");
|
|
||||||
|
|
||||||
case 23:
|
|
||||||
db.execSQL("CREATE TABLE IF NOT EXISTS key_signatures ("
|
|
||||||
+ "master_key_id INTEGER NOT NULL, "
|
|
||||||
+ "signer_key_id INTEGER NOT NULL, "
|
|
||||||
+ "PRIMARY KEY(master_key_id, signer_key_id), "
|
|
||||||
+ "FOREIGN KEY(master_key_id) REFERENCES keyrings_public(master_key_id) ON DELETE CASCADE"
|
|
||||||
+ ")");
|
|
||||||
|
|
||||||
case 24: {
|
|
||||||
db.execSQL("ALTER TABLE api_autocrypt_peers RENAME TO tmp");
|
|
||||||
db.execSQL("CREATE TABLE api_autocrypt_peers ("
|
|
||||||
+ "package_name TEXT NOT NULL, "
|
|
||||||
+ "identifier TEXT NOT NULL, "
|
|
||||||
+ "last_seen INTEGER, "
|
|
||||||
+ "last_seen_key INTEGER, "
|
|
||||||
+ "is_mutual INTEGER, "
|
|
||||||
+ "master_key_id INTEGER, "
|
|
||||||
+ "gossip_master_key_id INTEGER, "
|
|
||||||
+ "gossip_last_seen_key INTEGER, "
|
|
||||||
+ "gossip_origin INTEGER, "
|
|
||||||
+ "PRIMARY KEY(package_name, identifier), "
|
|
||||||
+ "FOREIGN KEY(package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE"
|
|
||||||
+ ")");
|
|
||||||
// Note: Keys from Autocrypt 0.X with state == "reset" (0) are dropped
|
|
||||||
db.execSQL("INSERT INTO api_autocrypt_peers " +
|
|
||||||
"(package_name, identifier, last_seen, gossip_last_seen_key, gossip_master_key_id, gossip_origin) " +
|
|
||||||
"SELECT package_name, identifier, last_updated, last_seen_key, master_key_id, 0 " +
|
|
||||||
"FROM tmp WHERE state = 1"); // Autocrypt 0.X, "gossip" -> now origin=autocrypt
|
|
||||||
db.execSQL("INSERT INTO api_autocrypt_peers " +
|
|
||||||
"(package_name, identifier, last_seen, gossip_last_seen_key, gossip_master_key_id, gossip_origin) " +
|
|
||||||
"SELECT package_name, identifier, last_updated, last_seen_key, master_key_id, 20 " +
|
|
||||||
"FROM tmp WHERE state = 2"); // "selected" keys -> now origin=dedup
|
|
||||||
db.execSQL("INSERT INTO api_autocrypt_peers " +
|
|
||||||
"(package_name, identifier, last_seen, last_seen_key, master_key_id, is_mutual) " +
|
|
||||||
"SELECT package_name, identifier, last_updated, last_seen_key, master_key_id, 0 " +
|
|
||||||
"FROM tmp WHERE state = 3"); // Autocrypt 0.X, state = "available"
|
|
||||||
db.execSQL("INSERT INTO api_autocrypt_peers " +
|
|
||||||
"(package_name, identifier, last_seen, last_seen_key, master_key_id, is_mutual) " +
|
|
||||||
"SELECT package_name, identifier, last_updated, last_seen_key, master_key_id, 1 " +
|
|
||||||
"FROM tmp WHERE state = 4"); // from Autocrypt 0.X, state = "mutual"
|
|
||||||
db.execSQL("DROP TABLE tmp");
|
|
||||||
|
|
||||||
db.execSQL("CREATE INDEX IF NOT EXISTS uids_by_email ON user_packets (email);");
|
|
||||||
db.execSQL("DROP INDEX keys_by_rank");
|
|
||||||
db.execSQL("CREATE INDEX keys_by_rank ON keys(rank, master_key_id);");
|
|
||||||
}
|
|
||||||
|
|
||||||
case 25: {
|
|
||||||
try {
|
|
||||||
migrateSecretKeysFromDbToLocalStorage(db, context);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("Error migrating secret keys! This is bad!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case 26:
|
|
||||||
migrateUpdatedKeysToKeyMetadataTable(db);
|
|
||||||
|
|
||||||
case 27:
|
|
||||||
renameApiAutocryptPeersTable(db);
|
|
||||||
|
|
||||||
case 28:
|
|
||||||
// drop old table from version 20
|
|
||||||
db.execSQL("DROP TABLE IF EXISTS api_accounts");
|
|
||||||
|
|
||||||
case 29:
|
|
||||||
recreateUnifiedKeyView(db);
|
|
||||||
|
|
||||||
case 30:
|
|
||||||
// ignore. this case only came up in an unreleased beta.
|
|
||||||
|
|
||||||
case 31:
|
|
||||||
addSubkeyValidFromField(db);
|
|
||||||
|
|
||||||
case 32:
|
|
||||||
recreateUnifiedKeyView(db);
|
|
||||||
|
|
||||||
case 33:
|
|
||||||
dropKeyMetadataForeignKey(db);
|
|
||||||
}
|
}
|
||||||
|
// recreate the unified key view on any upgrade
|
||||||
|
recreateDatabaseViews(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSubkeyValidFromField(SupportSQLiteDatabase db) {
|
private static void recreateDatabaseViews(SupportSQLiteDatabase db) {
|
||||||
try {
|
// for some reason those aren't created as part of the schema. so we do it here.
|
||||||
db.execSQL("ALTER TABLE keys ADD COLUMN validFrom INTEGER NOT NULL DEFAULT 0;");
|
db.execSQL("DROP VIEW IF EXISTS unifiedKeyView");
|
||||||
db.execSQL("UPDATE keys SET validFrom = creation");
|
db.execSQL(
|
||||||
} catch (SQLiteException e) {
|
"""
|
||||||
// column probably already existed, nvm this
|
CREATE VIEW unifiedKeyView AS
|
||||||
}
|
SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.user_id, user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, keys.can_certify, certs.verified,
|
||||||
}
|
(EXISTS (SELECT * FROM user_packets AS dups WHERE dups.master_key_id != keys.master_key_id AND dups.rank = 0 AND dups.name = user_packets.name COLLATE NOCASE AND dups.email = user_packets.email COLLATE NOCASE )) AS has_duplicate,
|
||||||
|
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.has_secret != 0)) AS has_any_secret,
|
||||||
|
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_encrypt != 0)) AS has_encrypt_key,
|
||||||
|
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_sign != 0)) AS has_sign_key,
|
||||||
|
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_authenticate != 0)) AS has_auth_key,
|
||||||
|
GROUP_CONCAT(DISTINCT aTI.package_name) AS autocrypt_package_names_csv,
|
||||||
|
GROUP_CONCAT(user_packets.user_id, '|||') AS user_id_list
|
||||||
|
FROM keys
|
||||||
|
INNER JOIN user_packets ON ( keys.master_key_id = user_packets.master_key_id AND user_packets.type IS NULL AND (user_packets.rank = 0 OR user_packets.is_revoked = 0))
|
||||||
|
LEFT JOIN certs ON ( keys.master_key_id = certs.master_key_id AND certs.verified = 1 )
|
||||||
|
LEFT JOIN autocrypt_peers AS aTI ON ( aTI.master_key_id = keys.master_key_id )
|
||||||
|
WHERE keys.rank = 0
|
||||||
|
GROUP BY keys.master_key_id;""");
|
||||||
|
db.execSQL("DROP VIEW IF EXISTS validKeys");
|
||||||
|
db.execSQL("""
|
||||||
|
CREATE VIEW validKeys AS
|
||||||
|
SELECT master_key_id, rank, key_id, key_size, key_curve_oid, algorithm, fingerprint, can_certify, can_sign, can_encrypt, can_authenticate, is_revoked, has_secret, is_secure, creation, expiry
|
||||||
|
FROM keys
|
||||||
|
WHERE is_revoked = 0 AND is_secure = 1 AND (expiry IS NULL OR expiry >= strftime('%s', 'now')) AND validFrom <= strftime('%s', 'now');
|
||||||
|
""");
|
||||||
|
db.execSQL("DROP VIEW IF EXISTS uidStatus");
|
||||||
|
db.execSQL("""
|
||||||
|
CREATE VIEW uidStatus AS
|
||||||
|
SELECT user_packets.email, MIN(certs.verified) AS key_status_int, user_packets.user_id, user_packets.master_key_id, COUNT(DISTINCT user_packets.master_key_id) AS candidates
|
||||||
|
FROM user_packets
|
||||||
|
JOIN validMasterKeys USING (master_key_id)
|
||||||
|
LEFT JOIN certs ON (certs.master_key_id = user_packets.master_key_id AND certs.rank = user_packets.rank AND certs.verified > 0)
|
||||||
|
WHERE user_packets.email IS NOT NULL
|
||||||
|
GROUP BY user_packets.email;
|
||||||
|
""");
|
||||||
|
db.execSQL("DROP VIEW IF EXISTS validMasterKeys");
|
||||||
|
db.execSQL("""
|
||||||
|
CREATE VIEW validMasterKeys AS
|
||||||
|
SELECT *
|
||||||
|
FROM validKeys
|
||||||
|
WHERE rank = 0;
|
||||||
|
""");
|
||||||
|
|
||||||
private void recreateUnifiedKeyView(SupportSQLiteDatabase db) {
|
|
||||||
// noinspection deprecation
|
|
||||||
db.execSQL("DROP VIEW IF EXISTS " + KeysModel.UNIFIEDKEYVIEW_VIEW_NAME);
|
|
||||||
db.execSQL(KeysModel.UNIFIEDKEYVIEW);
|
|
||||||
// noinspection deprecation
|
|
||||||
db.execSQL("DROP VIEW IF EXISTS " + KeysModel.VALIDKEYS_VIEW_NAME);
|
|
||||||
db.execSQL(KeysModel.VALIDKEYSVIEW);
|
|
||||||
// noinspection deprecation
|
|
||||||
db.execSQL("DROP VIEW IF EXISTS " + KeysModel.VALIDMASTERKEYS_VIEW_NAME);
|
|
||||||
db.execSQL(KeysModel.VALIDMASTERKEYSVIEW);
|
|
||||||
// noinspection deprecation
|
|
||||||
db.execSQL("DROP VIEW IF EXISTS " + UserPacketsModel.UIDSTATUS_VIEW_NAME);
|
|
||||||
db.execSQL(UserPacketsModel.UIDSTATUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dropKeyMetadataForeignKey(SupportSQLiteDatabase db) {
|
|
||||||
// noinspection deprecation
|
|
||||||
db.execSQL("ALTER TABLE " + KeyMetadataModel.TABLE_NAME + " RENAME TO metadata_tmp");
|
|
||||||
db.execSQL(KeyMetadataModel.CREATE_TABLE);
|
|
||||||
// noinspection deprecation
|
|
||||||
db.execSQL("INSERT INTO " + KeyMetadataModel.TABLE_NAME + " SELECT * FROM metadata_tmp");
|
|
||||||
db.execSQL("DROP TABLE metadata_tmp");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void migrateSecretKeysFromDbToLocalStorage(SupportSQLiteDatabase db, Context context) throws IOException {
|
|
||||||
LocalSecretKeyStorage localSecretKeyStorage = LocalSecretKeyStorage.getInstance(context);
|
|
||||||
Cursor cursor = db.query("SELECT master_key_id, key_ring_data FROM keyrings_secret");
|
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
long masterKeyId = cursor.getLong(0);
|
|
||||||
byte[] secretKeyBlob = cursor.getBlob(1);
|
|
||||||
localSecretKeyStorage.writeSecretKey(masterKeyId, secretKeyBlob);
|
|
||||||
}
|
|
||||||
cursor.close();
|
|
||||||
|
|
||||||
// we'll keep this around for now, but make sure to delete when migration looks ok!!
|
|
||||||
// db.execSQL("DROP TABLE keyrings_secret");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void migrateUpdatedKeysToKeyMetadataTable(SupportSQLiteDatabase db) {
|
|
||||||
try {
|
|
||||||
db.execSQL("ALTER TABLE updated_keys RENAME TO key_metadata;");
|
|
||||||
} catch (SQLException e) {
|
|
||||||
if (Constants.DEBUG) {
|
|
||||||
Timber.e(e, "Ignoring migration exception, this probably happened before");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renameApiAutocryptPeersTable(SupportSQLiteDatabase db) {
|
|
||||||
try {
|
|
||||||
db.execSQL("ALTER TABLE api_autocrypt_peers RENAME TO autocrypt_peers;");
|
|
||||||
} catch (SQLException e) {
|
|
||||||
if (Constants.DEBUG) {
|
|
||||||
Timber.e(e, "Ignoring migration exception, this probably happened before");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDowngrade() {
|
private void onDowngrade() {
|
||||||
@@ -468,7 +236,7 @@ public class KeychainDatabase {
|
|||||||
out.createNewFile();
|
out.createNewFile();
|
||||||
}
|
}
|
||||||
if (!in.canRead()) {
|
if (!in.canRead()) {
|
||||||
throw new IOException("Cannot read " + in.getName());
|
throw new IOException("Cannot read " + in.getName());
|
||||||
}
|
}
|
||||||
if (!out.canWrite()) {
|
if (!out.canWrite()) {
|
||||||
throw new IOException("Cannot write " + out.getName());
|
throw new IOException("Cannot write " + out.getName());
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
package org.sufficientlysecure.keychain.daos;
|
package org.sufficientlysecure.keychain.daos;
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||||
import androidx.sqlite.db.SupportSQLiteQuery;
|
import org.sufficientlysecure.keychain.Database;
|
||||||
import android.database.Cursor;
|
|
||||||
|
|
||||||
import com.squareup.sqldelight.RowMapper;
|
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractDao {
|
class AbstractDao {
|
||||||
@@ -22,8 +15,8 @@ class AbstractDao {
|
|||||||
this.databaseNotifyManager = databaseNotifyManager;
|
this.databaseNotifyManager = databaseNotifyManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
SupportSQLiteDatabase getReadableDb() {
|
Database getDatabase() {
|
||||||
return db.getReadableDatabase();
|
return db.getSqlDelightDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
SupportSQLiteDatabase getWritableDb() {
|
SupportSQLiteDatabase getWritableDb() {
|
||||||
@@ -33,32 +26,4 @@ class AbstractDao {
|
|||||||
DatabaseNotifyManager getDatabaseNotifyManager() {
|
DatabaseNotifyManager getDatabaseNotifyManager() {
|
||||||
return databaseNotifyManager;
|
return databaseNotifyManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
<T> List<T> mapAllRows(SupportSQLiteQuery query, RowMapper<T> mapper) {
|
|
||||||
ArrayList<T> result = new ArrayList<>();
|
|
||||||
try (Cursor cursor = getReadableDb().query(query)) {
|
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
T item = mapper.map(cursor);
|
|
||||||
result.add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
<T> T mapSingleRowOrThrow(SupportSQLiteQuery query, RowMapper<T> mapper) throws NotFoundException {
|
|
||||||
T result = mapSingleRow(query, mapper);
|
|
||||||
if (result == null) {
|
|
||||||
throw new NotFoundException();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
<T> T mapSingleRow(SupportSQLiteQuery query, RowMapper<T> mapper) {
|
|
||||||
try (Cursor cursor = getReadableDb().query(query)) {
|
|
||||||
if (cursor.moveToNext()) {
|
|
||||||
return mapper.map(cursor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,26 +18,25 @@
|
|||||||
package org.sufficientlysecure.keychain.daos;
|
package org.sufficientlysecure.keychain.daos;
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
|
||||||
|
|
||||||
import com.squareup.sqldelight.SqlDelightQuery;
|
import org.sufficientlysecure.keychain.ApiAllowedKeysQueries;
|
||||||
import org.sufficientlysecure.keychain.ApiAllowedKeysModel.InsertAllowedKey;
|
import org.sufficientlysecure.keychain.ApiAppsQueries;
|
||||||
import org.sufficientlysecure.keychain.ApiAppsModel;
|
import org.sufficientlysecure.keychain.Api_apps;
|
||||||
import org.sufficientlysecure.keychain.ApiAppsModel.DeleteByPackageName;
|
import org.sufficientlysecure.keychain.GetCertificate;
|
||||||
import org.sufficientlysecure.keychain.ApiAppsModel.InsertApiApp;
|
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.model.ApiAllowedKey;
|
|
||||||
import org.sufficientlysecure.keychain.model.ApiApp;
|
|
||||||
|
|
||||||
|
|
||||||
public class ApiAppDao extends AbstractDao {
|
public class ApiAppDao extends AbstractDao {
|
||||||
|
private final ApiAppsQueries apiAppsQueries = getDatabase().getApiAppsQueries();
|
||||||
|
private final ApiAllowedKeysQueries apiAllowedKeysQueries =
|
||||||
|
getDatabase().getApiAllowedKeysQueries();
|
||||||
|
|
||||||
public static ApiAppDao getInstance(Context context) {
|
public static ApiAppDao getInstance(Context context) {
|
||||||
KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context);
|
KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context);
|
||||||
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||||
@@ -45,95 +44,75 @@ public class ApiAppDao extends AbstractDao {
|
|||||||
return new ApiAppDao(keychainDatabase, databaseNotifyManager);
|
return new ApiAppDao(keychainDatabase, databaseNotifyManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApiAppDao(KeychainDatabase keychainDatabase, DatabaseNotifyManager databaseNotifyManager) {
|
private ApiAppDao(KeychainDatabase keychainDatabase,
|
||||||
|
DatabaseNotifyManager databaseNotifyManager) {
|
||||||
super(keychainDatabase, databaseNotifyManager);
|
super(keychainDatabase, databaseNotifyManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApiApp getApiApp(String packageName) {
|
public Api_apps getApiApp(String packageName) {
|
||||||
try (Cursor cursor = getReadableDb().query(ApiApp.FACTORY.selectByPackageName(packageName))) {
|
return apiAppsQueries.selectByPackageName(packageName).executeAsOneOrNull();
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
return ApiApp.FACTORY.selectByPackageNameMapper().map(cursor);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getApiAppCertificate(String packageName) {
|
public byte[] getApiAppCertificate(String packageName) {
|
||||||
try (Cursor cursor = getReadableDb().query(ApiApp.FACTORY.getCertificate(packageName))) {
|
GetCertificate getCertificate =
|
||||||
if (cursor.moveToFirst()) {
|
apiAppsQueries.getCertificate(packageName).executeAsOneOrNull();
|
||||||
return ApiApp.FACTORY.getCertificateMapper().map(cursor);
|
if (getCertificate == null) {
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return getCertificate.getPackage_signature();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void insertApiApp(ApiApp apiApp) {
|
public void insertApiApp(String packageName, byte[] signature) {
|
||||||
ApiApp existingApiApp = getApiApp(apiApp.package_name());
|
Api_apps existingApiApp = getApiApp(packageName);
|
||||||
if (existingApiApp != null) {
|
if (existingApiApp != null) {
|
||||||
if (!Arrays.equals(existingApiApp.package_signature(), apiApp.package_signature())) {
|
if (!Arrays.equals(existingApiApp.getPackage_signature(),
|
||||||
throw new IllegalStateException("Inserting existing api with different signature?!");
|
signature)) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Inserting existing api with different signature?!");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InsertApiApp statement = new ApiAppsModel.InsertApiApp(getWritableDb());
|
apiAppsQueries.insertApiApp(packageName, signature);
|
||||||
statement.bind(apiApp.package_name(), apiApp.package_signature());
|
getDatabaseNotifyManager().notifyApiAppChange(packageName);
|
||||||
statement.executeInsert();
|
}
|
||||||
|
|
||||||
getDatabaseNotifyManager().notifyApiAppChange(apiApp.package_name());
|
public void insertApiApp(Api_apps apiApp) {
|
||||||
|
Api_apps existingApiApp = getApiApp(apiApp.getPackage_name());
|
||||||
|
if (existingApiApp != null) {
|
||||||
|
if (!Arrays.equals(existingApiApp.getPackage_signature(),
|
||||||
|
apiApp.getPackage_signature())) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Inserting existing api with different signature?!");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
apiAppsQueries.insertApiApp(apiApp.getPackage_name(), apiApp.getPackage_signature());
|
||||||
|
getDatabaseNotifyManager().notifyApiAppChange(apiApp.getPackage_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteApiApp(String packageName) {
|
public void deleteApiApp(String packageName) {
|
||||||
DeleteByPackageName deleteByPackageName = new DeleteByPackageName(getWritableDb());
|
apiAppsQueries.deleteByPackageName(packageName);
|
||||||
deleteByPackageName.bind(packageName);
|
|
||||||
deleteByPackageName.executeUpdateDelete();
|
|
||||||
|
|
||||||
getDatabaseNotifyManager().notifyApiAppChange(packageName);
|
getDatabaseNotifyManager().notifyApiAppChange(packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashSet<Long> getAllowedKeyIdsForApp(String packageName) {
|
public HashSet<Long> getAllowedKeyIdsForApp(String packageName) {
|
||||||
SqlDelightQuery allowedKeys = ApiAllowedKey.FACTORY.getAllowedKeys(packageName);
|
return new HashSet<>(apiAllowedKeysQueries.getAllowedKeys(packageName).executeAsList());
|
||||||
HashSet<Long> keyIds = new HashSet<>();
|
|
||||||
try (Cursor cursor = getReadableDb().query(allowedKeys)) {
|
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
long allowedKeyId = ApiAllowedKey.FACTORY.getAllowedKeysMapper().map(cursor);
|
|
||||||
keyIds.add(allowedKeyId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return keyIds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveAllowedKeyIdsForApp(String packageName, Set<Long> allowedKeyIds) {
|
public void saveAllowedKeyIdsForApp(String packageName, Set<Long> allowedKeyIds) {
|
||||||
ApiAllowedKey.DeleteByPackageName deleteByPackageName = new ApiAllowedKey.DeleteByPackageName(getWritableDb());
|
apiAllowedKeysQueries.deleteByPackageName(packageName);
|
||||||
deleteByPackageName.bind(packageName);
|
|
||||||
deleteByPackageName.executeUpdateDelete();
|
|
||||||
|
|
||||||
InsertAllowedKey statement = new InsertAllowedKey(getWritableDb());
|
|
||||||
for (Long keyId : allowedKeyIds) {
|
for (Long keyId : allowedKeyIds) {
|
||||||
statement.bind(packageName, keyId);
|
apiAllowedKeysQueries.insertAllowedKey(packageName, keyId);
|
||||||
statement.execute();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getDatabaseNotifyManager().notifyApiAppChange(packageName);
|
getDatabaseNotifyManager().notifyApiAppChange(packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAllowedKeyIdForApp(String packageName, long allowedKeyId) {
|
public void addAllowedKeyIdForApp(String packageName, long allowedKeyId) {
|
||||||
InsertAllowedKey statement = new InsertAllowedKey(getWritableDb());
|
apiAllowedKeysQueries.insertAllowedKey(packageName, allowedKeyId);
|
||||||
statement.bind(packageName, allowedKeyId);
|
|
||||||
statement.executeInsert();
|
|
||||||
|
|
||||||
getDatabaseNotifyManager().notifyApiAppChange(packageName);
|
getDatabaseNotifyManager().notifyApiAppChange(packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ApiApp> getAllApiApps() {
|
public List<Api_apps> getAllApiApps() {
|
||||||
SqlDelightQuery query = ApiApp.FACTORY.selectAll();
|
return apiAppsQueries.selectAll().executeAsList();
|
||||||
|
|
||||||
ArrayList<ApiApp> result = new ArrayList<>();
|
|
||||||
try (Cursor cursor = getReadableDb().query(query)) {
|
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
ApiApp apiApp = ApiApp.FACTORY.selectAllMapper().map(cursor);
|
|
||||||
result.add(apiApp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,28 +18,26 @@
|
|||||||
package org.sufficientlysecure.keychain.daos;
|
package org.sufficientlysecure.keychain.daos;
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.squareup.sqldelight.SqlDelightQuery;
|
import androidx.annotation.Nullable;
|
||||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.DeleteByIdentifier;
|
import org.sufficientlysecure.keychain.AutocryptPeersQueries;
|
||||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.DeleteByMasterKeyId;
|
import org.sufficientlysecure.keychain.Autocrypt_peers;
|
||||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.InsertPeer;
|
|
||||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.UpdateGossipKey;
|
|
||||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.UpdateKey;
|
|
||||||
import org.sufficientlysecure.keychain.AutocryptPeersModel.UpdateLastSeen;
|
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer;
|
import org.sufficientlysecure.keychain.SelectAutocryptKeyStatus;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer.AutocryptKeyStatus;
|
import org.sufficientlysecure.keychain.SelectMasterKeyIdByIdentifier;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
|
import org.sufficientlysecure.keychain.model.GossipOrigin;
|
||||||
|
|
||||||
|
|
||||||
public class AutocryptPeerDao extends AbstractDao {
|
public class AutocryptPeerDao extends AbstractDao {
|
||||||
|
private final AutocryptPeersQueries autocryptPeersQueries =
|
||||||
|
getDatabase().getAutocryptPeersQueries();
|
||||||
|
|
||||||
public static AutocryptPeerDao getInstance(Context context) {
|
public static AutocryptPeerDao getInstance(Context context) {
|
||||||
KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context);
|
KeychainDatabase keychainDatabase = KeychainDatabase.getInstance(context);
|
||||||
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||||
@@ -47,100 +45,78 @@ public class AutocryptPeerDao extends AbstractDao {
|
|||||||
return new AutocryptPeerDao(keychainDatabase, databaseNotifyManager);
|
return new AutocryptPeerDao(keychainDatabase, databaseNotifyManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AutocryptPeerDao(KeychainDatabase database, DatabaseNotifyManager databaseNotifyManager) {
|
private AutocryptPeerDao(KeychainDatabase database,
|
||||||
|
DatabaseNotifyManager databaseNotifyManager) {
|
||||||
super(database, databaseNotifyManager);
|
super(database, databaseNotifyManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getMasterKeyIdForAutocryptPeer(String autocryptId) {
|
public Long getMasterKeyIdForAutocryptPeer(String autocryptId) {
|
||||||
SqlDelightQuery query = AutocryptPeer.FACTORY.selectMasterKeyIdByIdentifier(autocryptId);
|
SelectMasterKeyIdByIdentifier masterKeyId =
|
||||||
try (Cursor cursor = getReadableDb().query(query)) {
|
autocryptPeersQueries.selectMasterKeyIdByIdentifier(autocryptId)
|
||||||
if (cursor.moveToFirst()) {
|
.executeAsOneOrNull();
|
||||||
return AutocryptPeer.FACTORY.selectMasterKeyIdByIdentifierMapper().map(cursor);
|
if (masterKeyId != null) {
|
||||||
}
|
return masterKeyId.getMaster_key_id();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public AutocryptPeer getAutocryptPeer(String packageName, String autocryptId) {
|
public Autocrypt_peers getAutocryptPeer(String packageName, String autocryptId) {
|
||||||
List<AutocryptPeer> autocryptPeers = getAutocryptPeers(packageName, autocryptId);
|
return autocryptPeersQueries.selectByIdentifiers(packageName,
|
||||||
if (!autocryptPeers.isEmpty()) {
|
Collections.singleton(autocryptId)).executeAsOneOrNull();
|
||||||
return autocryptPeers.get(0);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<AutocryptPeer> getAutocryptPeers(String packageName, String... autocryptId) {
|
private List<Autocrypt_peers> getAutocryptPeers(String packageName, String... autocryptId) {
|
||||||
SqlDelightQuery query = AutocryptPeer.FACTORY.selectByIdentifiers(packageName, autocryptId);
|
return autocryptPeersQueries.selectByIdentifiers(packageName, Arrays.asList(autocryptId))
|
||||||
return mapAllRows(query, AutocryptPeer.PEER_MAPPER);
|
.executeAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AutocryptKeyStatus> getAutocryptKeyStatus(String packageName, String[] autocryptIds) {
|
public List<SelectAutocryptKeyStatus> getAutocryptKeyStatus(String packageName,
|
||||||
SqlDelightQuery query = AutocryptPeer.FACTORY.selectAutocryptKeyStatus(packageName, autocryptIds);
|
String[] autocryptIds) {
|
||||||
return mapAllRows(query, AutocryptPeer.KEY_STATUS_MAPPER);
|
return autocryptPeersQueries.selectAutocryptKeyStatus(packageName,
|
||||||
|
Arrays.asList(autocryptIds)).executeAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureAutocryptPeerExists(String packageName, String autocryptId) {
|
private void ensureAutocryptPeerExists(String packageName, String autocryptId) {
|
||||||
InsertPeer insertStatement = new InsertPeer(getWritableDb());
|
autocryptPeersQueries.insertPeer(packageName, autocryptId);
|
||||||
insertStatement.bind(packageName, autocryptId);
|
|
||||||
insertStatement.executeInsert();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void insertOrUpdateLastSeen(String packageName, String autocryptId, Date date) {
|
public void insertOrUpdateLastSeen(String packageName, String autocryptId, Date date) {
|
||||||
ensureAutocryptPeerExists(packageName, autocryptId);
|
ensureAutocryptPeerExists(packageName, autocryptId);
|
||||||
|
autocryptPeersQueries.updateLastSeen(packageName, autocryptId, date);
|
||||||
UpdateLastSeen updateStatement = new UpdateLastSeen(getWritableDb(), AutocryptPeer.FACTORY);
|
|
||||||
updateStatement.bind(packageName, autocryptId, date);
|
|
||||||
updateStatement.executeUpdateDelete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateKey(String packageName, String autocryptId, Date effectiveDate, long masterKeyId,
|
public void updateKey(String packageName, String autocryptId, Date effectiveDate,
|
||||||
|
long masterKeyId,
|
||||||
boolean isMutual) {
|
boolean isMutual) {
|
||||||
ensureAutocryptPeerExists(packageName, autocryptId);
|
ensureAutocryptPeerExists(packageName, autocryptId);
|
||||||
|
autocryptPeersQueries.updateKey(packageName, autocryptId, effectiveDate, masterKeyId,
|
||||||
UpdateKey updateStatement = new UpdateKey(getWritableDb(), AutocryptPeer.FACTORY);
|
isMutual);
|
||||||
updateStatement.bind(packageName, autocryptId, effectiveDate, masterKeyId, isMutual);
|
|
||||||
updateStatement.executeUpdateDelete();
|
|
||||||
|
|
||||||
getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId);
|
getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateKeyGossip(String packageName, String autocryptId, Date effectiveDate, long masterKeyId,
|
public void updateKeyGossip(String packageName, String autocryptId, Date effectiveDate,
|
||||||
|
long masterKeyId,
|
||||||
GossipOrigin origin) {
|
GossipOrigin origin) {
|
||||||
ensureAutocryptPeerExists(packageName, autocryptId);
|
ensureAutocryptPeerExists(packageName, autocryptId);
|
||||||
|
autocryptPeersQueries.updateGossipKey(packageName, autocryptId, effectiveDate, masterKeyId,
|
||||||
UpdateGossipKey updateStatement = new UpdateGossipKey(getWritableDb(), AutocryptPeer.FACTORY);
|
origin);
|
||||||
updateStatement.bind(packageName, autocryptId, effectiveDate, masterKeyId, origin);
|
|
||||||
updateStatement.executeUpdateDelete();
|
|
||||||
|
|
||||||
getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId);
|
getDatabaseNotifyManager().notifyAutocryptUpdate(autocryptId, masterKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AutocryptPeer> getAutocryptPeersForKey(long masterKeyId) {
|
public List<Autocrypt_peers> getAutocryptPeersForKey(long masterKeyId) {
|
||||||
ArrayList<AutocryptPeer> result = new ArrayList<>();
|
return autocryptPeersQueries.selectByMasterKeyId(masterKeyId).executeAsList();
|
||||||
SqlDelightQuery query = AutocryptPeer.FACTORY.selectByMasterKeyId(masterKeyId);
|
|
||||||
try (Cursor cursor = getReadableDb().query(query)) {
|
|
||||||
if (cursor.moveToNext()) {
|
|
||||||
AutocryptPeer autocryptPeer = AutocryptPeer.PEER_MAPPER.map(cursor);
|
|
||||||
result.add(autocryptPeer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteByIdentifier(String packageName, String autocryptId) {
|
public void deleteByIdentifier(String packageName, String autocryptId) {
|
||||||
Long masterKeyId = getMasterKeyIdForAutocryptPeer(autocryptId);
|
Long masterKeyId = getMasterKeyIdForAutocryptPeer(autocryptId);
|
||||||
DeleteByIdentifier deleteStatement = new DeleteByIdentifier(getReadableDb());
|
autocryptPeersQueries.deleteByIdentifier(packageName, autocryptId);
|
||||||
deleteStatement.bind(packageName, autocryptId);
|
|
||||||
deleteStatement.execute();
|
|
||||||
if (masterKeyId != null) {
|
if (masterKeyId != null) {
|
||||||
getDatabaseNotifyManager().notifyAutocryptDelete(autocryptId, masterKeyId);
|
getDatabaseNotifyManager().notifyAutocryptDelete(autocryptId, masterKeyId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteByMasterKeyId(long masterKeyId) {
|
public void deleteByMasterKeyId(long masterKeyId) {
|
||||||
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(getReadableDb());
|
autocryptPeersQueries.deleteByMasterKeyId(masterKeyId);
|
||||||
deleteStatement.bind(masterKeyId);
|
|
||||||
deleteStatement.execute();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,9 @@ package org.sufficientlysecure.keychain.daos;
|
|||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
|
||||||
|
|
||||||
import com.squareup.sqldelight.SqlDelightQuery;
|
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.model.Certification;
|
import org.sufficientlysecure.keychain.SelectVerifyingCertDetails;
|
||||||
import org.sufficientlysecure.keychain.model.Certification.CertDetails;
|
|
||||||
|
|
||||||
|
|
||||||
public class CertificationDao extends AbstractDao {
|
public class CertificationDao extends AbstractDao {
|
||||||
@@ -22,14 +19,8 @@ public class CertificationDao extends AbstractDao {
|
|||||||
super(keychainDatabase, databaseNotifyManager);
|
super(keychainDatabase, databaseNotifyManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CertDetails getVerifyingCertDetails(long masterKeyId, int userPacketRank) {
|
public SelectVerifyingCertDetails getVerifyingCertDetails(long masterKeyId, int userPacketRank) {
|
||||||
SqlDelightQuery query = Certification.FACTORY.selectVerifyingCertDetails(masterKeyId, userPacketRank);
|
return getDatabase().getCertsQueries().selectVerifyingCertDetails(masterKeyId, userPacketRank).executeAsOneOrNull();
|
||||||
try (Cursor cursor = getReadableDb().query(query)) {
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
return Certification.CERT_DETAILS_MAPPER.map(cursor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,95 +3,76 @@ package org.sufficientlysecure.keychain.daos;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
import com.squareup.sqldelight.TransactionWithoutReturn;
|
||||||
|
import kotlin.Unit;
|
||||||
import org.sufficientlysecure.keychain.CertsModel.InsertCert;
|
import kotlin.jvm.functions.Function1;
|
||||||
import org.sufficientlysecure.keychain.KeyRingsPublicModel.InsertKeyRingPublic;
|
import org.sufficientlysecure.keychain.Certs;
|
||||||
import org.sufficientlysecure.keychain.KeySignaturesModel.InsertKeySignature;
|
import org.sufficientlysecure.keychain.Database;
|
||||||
import org.sufficientlysecure.keychain.KeysModel.InsertKey;
|
import org.sufficientlysecure.keychain.Key_signatures;
|
||||||
import org.sufficientlysecure.keychain.UserPacketsModel.InsertUserPacket;
|
import org.sufficientlysecure.keychain.Keyrings_public;
|
||||||
import org.sufficientlysecure.keychain.model.Certification;
|
import org.sufficientlysecure.keychain.Keys;
|
||||||
import org.sufficientlysecure.keychain.model.KeyRingPublic;
|
import org.sufficientlysecure.keychain.User_packets;
|
||||||
import org.sufficientlysecure.keychain.model.KeySignature;
|
|
||||||
import org.sufficientlysecure.keychain.model.SubKey;
|
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket;
|
|
||||||
|
|
||||||
|
|
||||||
public class DatabaseBatchInteractor {
|
public class DatabaseBatchInteractor {
|
||||||
private final SupportSQLiteDatabase db;
|
private final Database db;
|
||||||
|
|
||||||
private final InsertKeyRingPublic insertKeyRingPublicStatement;
|
DatabaseBatchInteractor(Database db) {
|
||||||
private final InsertKey insertSubKeyStatement;
|
|
||||||
private final InsertUserPacket insertUserPacketStatement;
|
|
||||||
private final InsertCert insertCertificationStatement;
|
|
||||||
private final InsertKeySignature insertKeySignerStatement;
|
|
||||||
|
|
||||||
DatabaseBatchInteractor(SupportSQLiteDatabase db) {
|
|
||||||
this.db = db;
|
this.db = db;
|
||||||
|
|
||||||
insertKeyRingPublicStatement = KeyRingPublic.createInsertStatement(db);
|
|
||||||
insertSubKeyStatement = SubKey.createInsertStatement(db);
|
|
||||||
insertUserPacketStatement = UserPacket.createInsertStatement(db);
|
|
||||||
insertCertificationStatement = Certification.createInsertStatement(db);
|
|
||||||
insertKeySignerStatement = KeySignature.createInsertStatement(db);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SupportSQLiteDatabase getDb() {
|
|
||||||
return db;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void applyBatch(List<BatchOp> operations) {
|
public void applyBatch(List<BatchOp> operations) {
|
||||||
for (BatchOp op : operations) {
|
db.transaction(true,
|
||||||
if (op.keyRingPublic != null) {
|
(Function1<TransactionWithoutReturn, Unit>) transactionWithoutReturn -> {
|
||||||
op.keyRingPublic.bindTo(insertKeyRingPublicStatement);
|
for (BatchOp op : operations) {
|
||||||
insertKeyRingPublicStatement.executeInsert();
|
if (op.keyRingPublic != null) {
|
||||||
} else if (op.subKey != null) {
|
db.getKeyRingsPublicQueries().insertKeyRingPublic(op.keyRingPublic);
|
||||||
op.subKey.bindTo(insertSubKeyStatement);
|
} else if (op.subKey != null) {
|
||||||
insertSubKeyStatement.executeInsert();
|
db.getKeysQueries().insertKey(op.subKey);
|
||||||
} else if (op.userPacket != null) {
|
} else if (op.userPacket != null) {
|
||||||
op.userPacket.bindTo(insertUserPacketStatement);
|
db.getUserPacketsQueries().insertUserPacket(op.userPacket);
|
||||||
insertUserPacketStatement.executeInsert();
|
} else if (op.certification != null) {
|
||||||
} else if (op.certification != null) {
|
db.getCertsQueries().insertCert(op.certification);
|
||||||
op.certification.bindTo(insertCertificationStatement);
|
} else if (op.keySignature != null) {
|
||||||
insertCertificationStatement.executeInsert();
|
db.getKeySignaturesQueries().insertKeySignature(op.keySignature);
|
||||||
} else if (op.keySignature != null) {
|
} else {
|
||||||
op.keySignature.bindTo(insertKeySignerStatement);
|
throw new IllegalStateException();
|
||||||
insertKeySignerStatement.executeInsert();
|
}
|
||||||
} else {
|
}
|
||||||
throw new IllegalStateException();
|
return Unit.INSTANCE;
|
||||||
}
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BatchOp createInsertKeyRingPublic(KeyRingPublic keyRingPublic) {
|
public static BatchOp createInsertKeyRingPublic(Keyrings_public keyRingPublic) {
|
||||||
return new BatchOp(keyRingPublic, null, null, null, null);
|
return new BatchOp(keyRingPublic, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BatchOp createInsertSubKey(SubKey subKey) {
|
static BatchOp createInsertSubKey(Keys subKey) {
|
||||||
return new BatchOp(null, subKey, null, null, null);
|
return new BatchOp(null, subKey, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BatchOp createInsertUserPacket(UserPacket userPacket) {
|
public static BatchOp createInsertUserPacket(User_packets userPacket) {
|
||||||
return new BatchOp(null, null, userPacket, null, null);
|
return new BatchOp(null, null, userPacket, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BatchOp createInsertCertification(Certification certification) {
|
public static BatchOp createInsertCertification(Certs certification) {
|
||||||
return new BatchOp(null, null, null, certification, null);
|
return new BatchOp(null, null, null, certification, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BatchOp createInsertSignerKey(KeySignature keySignature) {
|
static BatchOp createInsertSignerKey(Key_signatures keySignature) {
|
||||||
return new BatchOp(null, null, null, null, keySignature);
|
return new BatchOp(null, null, null, null, keySignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class BatchOp {
|
static class BatchOp {
|
||||||
final KeyRingPublic keyRingPublic;
|
final Keyrings_public keyRingPublic;
|
||||||
final SubKey subKey;
|
final Keys subKey;
|
||||||
final UserPacket userPacket;
|
final User_packets userPacket;
|
||||||
final Certification certification;
|
final Certs certification;
|
||||||
final KeySignature keySignature;
|
final Key_signatures keySignature;
|
||||||
|
|
||||||
BatchOp(KeyRingPublic keyRingPublic, SubKey subKey, UserPacket userPacket,
|
BatchOp(Keyrings_public keyRingPublic, Keys subKey, User_packets userPacket,
|
||||||
Certification certification, KeySignature keySignature) {
|
Certs certification, Key_signatures keySignature) {
|
||||||
this.subKey = subKey;
|
this.subKey = subKey;
|
||||||
this.keyRingPublic = keyRingPublic;
|
this.keyRingPublic = keyRingPublic;
|
||||||
this.userPacket = userPacket;
|
this.userPacket = userPacket;
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
package org.sufficientlysecure.keychain.daos;
|
package org.sufficientlysecure.keychain.daos;
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
|
||||||
|
|
||||||
import com.squareup.sqldelight.SqlDelightQuery;
|
import org.sufficientlysecure.keychain.KeyMetadataQueries;
|
||||||
import org.sufficientlysecure.keychain.KeyMetadataModel.ReplaceKeyMetadata;
|
import org.sufficientlysecure.keychain.Key_metadata;
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.model.KeyMetadata;
|
|
||||||
|
|
||||||
|
|
||||||
public class KeyMetadataDao extends AbstractDao {
|
public class KeyMetadataDao extends AbstractDao {
|
||||||
|
KeyMetadataQueries queries = getDatabase().getKeyMetadataQueries();
|
||||||
|
|
||||||
public static KeyMetadataDao create(Context context) {
|
public static KeyMetadataDao create(Context context) {
|
||||||
KeychainDatabase database = KeychainDatabase.getInstance(context);
|
KeychainDatabase database = KeychainDatabase.getInstance(context);
|
||||||
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||||
@@ -27,38 +26,21 @@ public class KeyMetadataDao extends AbstractDao {
|
|||||||
super(database, databaseNotifyManager);
|
super(database, databaseNotifyManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyMetadata getKeyMetadata(long masterKeyId) {
|
public Key_metadata getKeyMetadata(long masterKeyId) {
|
||||||
SqlDelightQuery query = KeyMetadata.FACTORY.selectByMasterKeyId(masterKeyId);
|
return queries.selectByMasterKeyId(masterKeyId).executeAsOneOrNull();
|
||||||
try (Cursor cursor = getReadableDb().query(query)) {
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
return KeyMetadata.FACTORY.selectByMasterKeyIdMapper().map(cursor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetAllLastUpdatedTimes() {
|
public void resetAllLastUpdatedTimes() {
|
||||||
new KeyMetadata.DeleteAllLastUpdatedTimes(getWritableDb()).execute();
|
queries.deleteAllLastUpdatedTimes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renewKeyLastUpdatedTime(long masterKeyId, boolean seenOnKeyservers) {
|
public void renewKeyLastUpdatedTime(long masterKeyId, boolean seenOnKeyservers) {
|
||||||
ReplaceKeyMetadata replaceStatement = new ReplaceKeyMetadata(getWritableDb(), KeyMetadata.FACTORY);
|
queries.replaceKeyMetadata(masterKeyId, new Date(), seenOnKeyservers);
|
||||||
replaceStatement.bind(masterKeyId, new Date(), seenOnKeyservers);
|
|
||||||
replaceStatement.executeInsert();
|
|
||||||
|
|
||||||
getDatabaseNotifyManager().notifyKeyMetadataChange(masterKeyId);
|
getDatabaseNotifyManager().notifyKeyMetadataChange(masterKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<byte[]> getFingerprintsForKeysOlderThan(long olderThan, TimeUnit timeUnit) {
|
public List<byte[]> getFingerprintsForKeysOlderThan(long olderThan, TimeUnit timeUnit) {
|
||||||
SqlDelightQuery query = KeyMetadata.FACTORY.selectFingerprintsForKeysOlderThan(new Date(timeUnit.toMillis(olderThan)));
|
return queries.selectFingerprintsForKeysOlderThan(new Date(timeUnit.toMillis(olderThan)))
|
||||||
|
.executeAsList();
|
||||||
List<byte[]> fingerprintList = new ArrayList<>();
|
|
||||||
try (Cursor cursor = getReadableDb().query(query)) {
|
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
byte[] fingerprint = KeyMetadata.FACTORY.selectFingerprintsForKeysOlderThanMapper().map(cursor);
|
|
||||||
fingerprintList.add(fingerprint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fingerprintList;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,22 +20,23 @@ package org.sufficientlysecure.keychain.daos;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
|
||||||
import androidx.annotation.WorkerThread;
|
|
||||||
|
|
||||||
import com.squareup.sqldelight.SqlDelightQuery;
|
import androidx.annotation.WorkerThread;
|
||||||
|
import com.squareup.sqldelight.Query;
|
||||||
|
import com.squareup.sqldelight.db.SqlCursor;
|
||||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||||
|
import org.sufficientlysecure.keychain.KeyRingsPublicQueries;
|
||||||
|
import org.sufficientlysecure.keychain.KeySignaturesQueries;
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.model.Certification;
|
import org.sufficientlysecure.keychain.Keyrings_public;
|
||||||
import org.sufficientlysecure.keychain.model.KeyRingPublic;
|
import org.sufficientlysecure.keychain.Keys;
|
||||||
import org.sufficientlysecure.keychain.model.KeySignature;
|
import org.sufficientlysecure.keychain.KeysQueries;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UserId;
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket;
|
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
||||||
@@ -49,9 +50,12 @@ import timber.log.Timber;
|
|||||||
public class KeyRepository extends AbstractDao {
|
public class KeyRepository extends AbstractDao {
|
||||||
final LocalPublicKeyStorage mLocalPublicKeyStorage;
|
final LocalPublicKeyStorage mLocalPublicKeyStorage;
|
||||||
final LocalSecretKeyStorage localSecretKeyStorage;
|
final LocalSecretKeyStorage localSecretKeyStorage;
|
||||||
|
private final KeysQueries keysQueries = getDatabase().getKeysQueries();
|
||||||
|
|
||||||
OperationLog mLog;
|
OperationLog mLog;
|
||||||
int mIndent;
|
int mIndent;
|
||||||
|
private final KeyRingsPublicQueries keyRingsPublicQueries = getDatabase().getKeyRingsPublicQueries();
|
||||||
|
private final KeySignaturesQueries keySignaturesQueries = getDatabase().getKeySignaturesQueries();
|
||||||
|
|
||||||
public static KeyRepository create(Context context) {
|
public static KeyRepository create(Context context) {
|
||||||
LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context);
|
LocalPublicKeyStorage localPublicKeyStorage = LocalPublicKeyStorage.getInstance(context);
|
||||||
@@ -59,14 +63,16 @@ public class KeyRepository extends AbstractDao {
|
|||||||
KeychainDatabase database = KeychainDatabase.getInstance(context);
|
KeychainDatabase database = KeychainDatabase.getInstance(context);
|
||||||
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context);
|
||||||
|
|
||||||
return new KeyRepository(database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage);
|
return new KeyRepository(database, databaseNotifyManager, localPublicKeyStorage,
|
||||||
|
localSecretKeyStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeyRepository(KeychainDatabase database,
|
private KeyRepository(KeychainDatabase database,
|
||||||
DatabaseNotifyManager databaseNotifyManager,
|
DatabaseNotifyManager databaseNotifyManager,
|
||||||
LocalPublicKeyStorage localPublicKeyStorage,
|
LocalPublicKeyStorage localPublicKeyStorage,
|
||||||
LocalSecretKeyStorage localSecretKeyStorage) {
|
LocalSecretKeyStorage localSecretKeyStorage) {
|
||||||
this(database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage, new OperationLog(), 0);
|
this(database, databaseNotifyManager, localPublicKeyStorage, localSecretKeyStorage,
|
||||||
|
new OperationLog(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyRepository(KeychainDatabase database,
|
KeyRepository(KeychainDatabase database,
|
||||||
@@ -101,7 +107,8 @@ public class KeyRepository extends AbstractDao {
|
|||||||
mLog = new OperationLog();
|
mLog = new OperationLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long masterKeyId) throws NotFoundException {
|
public CanonicalizedPublicKeyRing getCanonicalizedPublicKeyRing(long masterKeyId)
|
||||||
|
throws NotFoundException {
|
||||||
UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
|
UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
|
||||||
if (unifiedKeyInfo == null) {
|
if (unifiedKeyInfo == null) {
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
@@ -111,7 +118,8 @@ public class KeyRepository extends AbstractDao {
|
|||||||
return new CanonicalizedPublicKeyRing(publicKeyData, unifiedKeyInfo.verified());
|
return new CanonicalizedPublicKeyRing(publicKeyData, unifiedKeyInfo.verified());
|
||||||
}
|
}
|
||||||
|
|
||||||
public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(long masterKeyId) throws NotFoundException {
|
public CanonicalizedSecretKeyRing getCanonicalizedSecretKeyRing(long masterKeyId)
|
||||||
|
throws NotFoundException {
|
||||||
UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
|
UnifiedKeyInfo unifiedKeyInfo = getUnifiedKeyInfo(masterKeyId);
|
||||||
if (unifiedKeyInfo == null || !unifiedKeyInfo.has_any_secret()) {
|
if (unifiedKeyInfo == null || !unifiedKeyInfo.has_any_secret()) {
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
@@ -124,75 +132,85 @@ public class KeyRepository extends AbstractDao {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> getAllMasterKeyIds() {
|
public List<Long> getAllMasterKeyIds() {
|
||||||
SqlDelightQuery query = KeyRingPublic.FACTORY.selectAllMasterKeyIds();
|
return keyRingsPublicQueries.selectAllMasterKeyIds().executeAsList();
|
||||||
return mapAllRows(query, KeySignature.FACTORY.selectMasterKeyIdsBySignerMapper());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> getMasterKeyIdsBySigner(List<Long> signerMasterKeyIds) {
|
public List<Long> getMasterKeyIdsBySigner(List<Long> signerMasterKeyIds) {
|
||||||
long[] signerKeyIds = getLongListAsArray(signerMasterKeyIds);
|
return keySignaturesQueries.selectMasterKeyIdsBySigner(signerMasterKeyIds).executeAsList();
|
||||||
SqlDelightQuery query = KeySignature.FACTORY.selectMasterKeyIdsBySigner(signerKeyIds);
|
|
||||||
return mapAllRows(query, KeySignature.FACTORY.selectMasterKeyIdsBySignerMapper());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getMasterKeyIdBySubkeyId(long subKeyId) {
|
public Long getMasterKeyIdBySubkeyId(long subKeyId) {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectMasterKeyIdBySubkey(subKeyId);
|
return keysQueries.selectMasterKeyIdBySubkey(subKeyId).executeAsOneOrNull();
|
||||||
return mapSingleRow(query, SubKey.FACTORY.selectMasterKeyIdBySubkeyMapper());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnifiedKeyInfo getUnifiedKeyInfo(long masterKeyId) {
|
public UnifiedKeyInfo getUnifiedKeyInfo(long masterKeyId) {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyId(masterKeyId);
|
return keysQueries.selectUnifiedKeyInfoByMasterKeyId(masterKeyId, UnifiedKeyInfo::create).executeAsOneOrNull();
|
||||||
return mapSingleRow(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UnifiedKeyInfo> getUnifiedKeyInfo(long... masterKeyIds) {
|
public List<UnifiedKeyInfo> getUnifiedKeyInfo(long... masterKeyIds) {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoByMasterKeyIds(masterKeyIds);
|
return keysQueries.selectUnifiedKeyInfoByMasterKeyIds(getLongArrayAsList(masterKeyIds), UnifiedKeyInfo::create)
|
||||||
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
|
.executeAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UnifiedKeyInfo> getUnifiedKeyInfosByMailAddress(String mailAddress) {
|
public List<UnifiedKeyInfo> getUnifiedKeyInfosByMailAddress(String mailAddress) {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%');
|
return keysQueries.selectUnifiedKeyInfoSearchMailAddress('%' + mailAddress + '%', UnifiedKeyInfo::create)
|
||||||
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
|
.executeAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UnifiedKeyInfo> getAllUnifiedKeyInfo() {
|
public List<UnifiedKeyInfo> getAllUnifiedKeyInfo() {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfo();
|
return keysQueries.selectAllUnifiedKeyInfo(UnifiedKeyInfo::create).executeAsList();
|
||||||
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithSecret() {
|
public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithSecret() {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfoWithSecret();
|
return keysQueries.selectAllUnifiedKeyInfoWithSecret(UnifiedKeyInfo::create).executeAsList();
|
||||||
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithAuthKeySecret() {
|
public List<UnifiedKeyInfo> getAllUnifiedKeyInfoWithAuthKeySecret() {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectAllUnifiedKeyInfoWithAuthKeySecret();
|
return keysQueries.selectAllUnifiedKeyInfoWithAuthKeySecret(UnifiedKeyInfo::create).executeAsList();
|
||||||
return mapAllRows(query, SubKey.UNIFIED_KEY_INFO_MAPPER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UserId> getUserIds(long... masterKeyIds) {
|
public List<UserId> getUserIds(long... masterKeyIds) {
|
||||||
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyIds);
|
return getDatabase().getUserPacketsQueries()
|
||||||
return mapAllRows(query, UserPacket.USER_ID_MAPPER);
|
.selectUserIdsByMasterKeyId(getLongArrayAsList(masterKeyIds), UserId::create).executeAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public List<String> getConfirmedUserIds(long masterKeyId) {
|
public List<String> getConfirmedUserIds(long masterKeyId) {
|
||||||
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyIdAndVerification(
|
return getDatabase().getUserPacketsQueries()
|
||||||
Certification.FACTORY, masterKeyId, VerificationStatus.VERIFIED_SECRET);
|
.selectUserIdsByMasterKeyIdAndVerification(masterKeyId,
|
||||||
return mapAllRows(query, cursor -> UserPacket.USER_ID_MAPPER.map(cursor).user_id());
|
VerificationStatus.VERIFIED_SECRET, (
|
||||||
|
master_key_id,
|
||||||
|
rank,
|
||||||
|
user_id,
|
||||||
|
name,
|
||||||
|
email,
|
||||||
|
comment,
|
||||||
|
is_primary,
|
||||||
|
is_revoked,
|
||||||
|
verified_int
|
||||||
|
|
||||||
|
) -> user_id).executeAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SubKey> getSubKeysByMasterKeyId(long masterKeyId) {
|
public List<Keys> getSubKeysByMasterKeyId(long masterKeyId) {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectSubkeysByMasterKeyId(masterKeyId);
|
return keysQueries.selectSubkeysByMasterKeyId(masterKeyId).executeAsList();
|
||||||
return mapAllRows(query, SubKey.SUBKEY_MAPPER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SecretKeyType getSecretKeyType(long keyId) throws NotFoundException {
|
public SecretKeyType getSecretKeyType(long keyId) throws NotFoundException {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectSecretKeyType(keyId);
|
try {
|
||||||
return mapSingleRowOrThrow(query, SubKey.SKT_MAPPER);
|
return keysQueries.selectSecretKeyType(keyId).executeAsOne();
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getFingerprintByKeyId(long keyId) throws NotFoundException {
|
public byte[] getFingerprintByKeyId(long keyId) throws NotFoundException {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectFingerprintByKeyId(keyId);
|
try {
|
||||||
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectFingerprintByKeyIdMapper());
|
return keysQueries.selectFingerprintByKeyId(keyId).executeAsOne();
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] getKeyRingAsArmoredData(byte[] data) throws IOException {
|
private byte[] getKeyRingAsArmoredData(byte[] data) throws IOException {
|
||||||
@@ -205,23 +223,26 @@ public class KeyRepository extends AbstractDao {
|
|||||||
return bos.toByteArray();
|
return bos.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPublicKeyRingAsArmoredString(long masterKeyId) throws NotFoundException, IOException {
|
public String getPublicKeyRingAsArmoredString(long masterKeyId)
|
||||||
|
throws NotFoundException, IOException {
|
||||||
byte[] data = loadPublicKeyRingData(masterKeyId);
|
byte[] data = loadPublicKeyRingData(masterKeyId);
|
||||||
byte[] armoredData = getKeyRingAsArmoredData(data);
|
byte[] armoredData = getKeyRingAsArmoredData(data);
|
||||||
return new String(armoredData);
|
return new String(armoredData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getSecretKeyRingAsArmoredData(long masterKeyId) throws NotFoundException, IOException {
|
public byte[] getSecretKeyRingAsArmoredData(long masterKeyId)
|
||||||
|
throws NotFoundException, IOException {
|
||||||
byte[] data = loadSecretKeyRingData(masterKeyId);
|
byte[] data = loadSecretKeyRingData(masterKeyId);
|
||||||
return getKeyRingAsArmoredData(data);
|
return getKeyRingAsArmoredData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final byte[] loadPublicKeyRingData(long masterKeyId) throws NotFoundException {
|
public final byte[] loadPublicKeyRingData(long masterKeyId) throws NotFoundException {
|
||||||
SqlDelightQuery query = KeyRingPublic.FACTORY.selectByMasterKeyId(masterKeyId);
|
Query<Keyrings_public> keyringsPublicQuery =
|
||||||
try (Cursor cursor = getReadableDb().query(query)) {
|
keyRingsPublicQueries.selectByMasterKeyId(masterKeyId);
|
||||||
if (cursor.moveToFirst()) {
|
try (SqlCursor cursor = keyringsPublicQuery.execute()) {
|
||||||
KeyRingPublic keyRingPublic = KeyRingPublic.MAPPER.map(cursor);
|
if (cursor.next()) {
|
||||||
byte[] keyRingData = keyRingPublic.key_ring_data();
|
Keyrings_public keyRingPublic = keyringsPublicQuery.getMapper().invoke(cursor);
|
||||||
|
byte[] keyRingData = keyRingPublic.getKey_ring_data();
|
||||||
if (keyRingData == null) {
|
if (keyRingData == null) {
|
||||||
keyRingData = mLocalPublicKeyStorage.readPublicKey(masterKeyId);
|
keyRingData = mLocalPublicKeyStorage.readPublicKey(masterKeyId);
|
||||||
}
|
}
|
||||||
@@ -243,18 +264,16 @@ public class KeyRepository extends AbstractDao {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getSecretSignId(long masterKeyId) throws NotFoundException {
|
public long getSecretSignId(long masterKeyId) throws NotFoundException {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyId(masterKeyId);
|
return keysQueries.selectEffectiveSignKeyIdByMasterKeyId(masterKeyId).executeAsOneOrNull();
|
||||||
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveSignKeyIdByMasterKeyIdMapper());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getEffectiveAuthenticationKeyId(long masterKeyId) throws NotFoundException {
|
public long getEffectiveAuthenticationKeyId(long masterKeyId) throws NotFoundException {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyId(masterKeyId);
|
return keysQueries.selectEffectiveAuthKeyIdByMasterKeyId(masterKeyId).executeAsOneOrNull();
|
||||||
return mapSingleRowOrThrow(query, SubKey.FACTORY.selectEffectiveAuthKeyIdByMasterKeyIdMapper());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> getPublicEncryptionIds(long masterKeyId) {
|
public List<Long> getPublicEncryptionIds(long masterKeyId) {
|
||||||
SqlDelightQuery query = SubKey.FACTORY.selectEffectiveEncryptionKeyIdsByMasterKeyId(masterKeyId);
|
return keysQueries.selectEffectiveEncryptionKeyIdsByMasterKeyId(masterKeyId)
|
||||||
return mapAllRows(query, SubKey.FACTORY.selectEffectiveEncryptionKeyIdsByMasterKeyIdMapper());
|
.executeAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class NotFoundException extends Exception {
|
public static class NotFoundException extends Exception {
|
||||||
@@ -274,4 +293,13 @@ public class KeyRepository extends AbstractDao {
|
|||||||
}
|
}
|
||||||
return longs;
|
return longs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Long> getLongArrayAsList(long[] longList) {
|
||||||
|
Long[] longs = new Long[longList.length];
|
||||||
|
int i = 0;
|
||||||
|
for (Long aLong : longList) {
|
||||||
|
longs[i++] = aLong;
|
||||||
|
}
|
||||||
|
return Arrays.asList(longs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,24 +25,23 @@ import java.util.Collections;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.collection.LongSparseArray;
|
import androidx.collection.LongSparseArray;
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||||
import org.openintents.openpgp.util.OpenPgpUtils;
|
import org.openintents.openpgp.util.OpenPgpUtils;
|
||||||
import org.sufficientlysecure.keychain.KeyRingsPublicModel.DeleteByMasterKeyId;
|
import org.sufficientlysecure.keychain.Certs;
|
||||||
|
import org.sufficientlysecure.keychain.Key_signatures;
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.KeysModel.UpdateHasSecretByKeyId;
|
import org.sufficientlysecure.keychain.Keyrings_public;
|
||||||
import org.sufficientlysecure.keychain.KeysModel.UpdateHasSecretByMasterKeyId;
|
import org.sufficientlysecure.keychain.Keys;
|
||||||
|
import org.sufficientlysecure.keychain.KeysQueries;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.User_packets;
|
||||||
|
import org.sufficientlysecure.keychain.UtilQueries;
|
||||||
import org.sufficientlysecure.keychain.daos.DatabaseBatchInteractor.BatchOp;
|
import org.sufficientlysecure.keychain.daos.DatabaseBatchInteractor.BatchOp;
|
||||||
import org.sufficientlysecure.keychain.model.Certification;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.model.KeyRingPublic;
|
|
||||||
import org.sufficientlysecure.keychain.model.KeySignature;
|
|
||||||
import org.sufficientlysecure.keychain.model.SubKey;
|
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||||
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
||||||
@@ -114,7 +113,7 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.databaseNotifyManager = databaseNotifyManager;
|
this.databaseNotifyManager = databaseNotifyManager;
|
||||||
this.autocryptPeerDao = autocryptPeerDao;
|
this.autocryptPeerDao = autocryptPeerDao;
|
||||||
this.databaseBatchInteractor = new DatabaseBatchInteractor(getWritableDb());
|
this.databaseBatchInteractor = new DatabaseBatchInteractor(getDatabase());
|
||||||
}
|
}
|
||||||
|
|
||||||
private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() {
|
private LongSparseArray<CanonicalizedPublicKey> getTrustedMasterKeys() {
|
||||||
@@ -193,7 +192,7 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
log(LogType.MSG_IP_INSERT_KEYRING);
|
log(LogType.MSG_IP_INSERT_KEYRING);
|
||||||
|
|
||||||
byte[] encodedRingIfDbCachable = encodedKeyRing.length < MAX_CACHED_KEY_SIZE ? encodedKeyRing : null;
|
byte[] encodedRingIfDbCachable = encodedKeyRing.length < MAX_CACHED_KEY_SIZE ? encodedKeyRing : null;
|
||||||
KeyRingPublic keyRingPublic = KeyRingPublic.create(masterKeyId, encodedRingIfDbCachable);
|
Keyrings_public keyRingPublic = new Keyrings_public(masterKeyId, encodedRingIfDbCachable);
|
||||||
operations.add(DatabaseBatchInteractor.createInsertKeyRingPublic(keyRingPublic));
|
operations.add(DatabaseBatchInteractor.createInsertKeyRingPublic(keyRingPublic));
|
||||||
|
|
||||||
log(LogType.MSG_IP_INSERT_SUBKEYS);
|
log(LogType.MSG_IP_INSERT_SUBKEYS);
|
||||||
@@ -239,9 +238,12 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SubKey subKey = SubKey.create(masterKeyId, rank, key.getKeyId(),
|
long creationUnixTime = creation.getTime() / 1000;
|
||||||
|
Long expiryUnixTime = expiry != null ? expiry.getTime() / 1000 : null;
|
||||||
|
long validFromTime = bindingSignatureTime.getTime() / 1000;
|
||||||
|
Keys subKey = new Keys(masterKeyId, rank, key.getKeyId(),
|
||||||
key.getBitStrength(), key.getCurveOid(), key.getAlgorithm(), key.getFingerprint(),
|
key.getBitStrength(), key.getCurveOid(), key.getAlgorithm(), key.getFingerprint(),
|
||||||
c, s, e, a, key.isRevoked(), SecretKeyType.UNAVAILABLE, key.isSecure(), creation, expiry, bindingSignatureTime);
|
c, s, e, a, key.isRevoked(), SecretKeyType.UNAVAILABLE, key.isSecure(), creationUnixTime, expiryUnixTime, validFromTime);
|
||||||
operations.add(DatabaseBatchInteractor.createInsertSubKey(subKey));
|
operations.add(DatabaseBatchInteractor.createInsertSubKey(subKey));
|
||||||
|
|
||||||
++rank;
|
++rank;
|
||||||
@@ -300,7 +302,7 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
|
|
||||||
// keep a note about the issuer of this key signature
|
// keep a note about the issuer of this key signature
|
||||||
if (!signerKeyIds.contains(certId)) {
|
if (!signerKeyIds.contains(certId)) {
|
||||||
KeySignature keySignature = KeySignature.create(masterKeyId, certId);
|
Key_signatures keySignature = new Key_signatures(masterKeyId, certId);
|
||||||
operations.add(DatabaseBatchInteractor.createInsertSignerKey(keySignature));
|
operations.add(DatabaseBatchInteractor.createInsertSignerKey(keySignature));
|
||||||
signerKeyIds.add(certId);
|
signerKeyIds.add(certId);
|
||||||
}
|
}
|
||||||
@@ -468,7 +470,7 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) {
|
for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) {
|
||||||
UserPacketItem item = uids.get(userIdRank);
|
UserPacketItem item = uids.get(userIdRank);
|
||||||
Long type = item.type != null ? item.type.longValue() : null;
|
Long type = item.type != null ? item.type.longValue() : null;
|
||||||
UserPacket userPacket = UserPacket.create(masterKeyId, userIdRank, type, item.userId, item.name, item.email,
|
User_packets userPacket = new User_packets(masterKeyId, userIdRank, type, item.userId, item.name, item.email,
|
||||||
item.comment, item.attributeData, item.isPrimary, item.selfRevocation != null);
|
item.comment, item.attributeData, item.isPrimary, item.selfRevocation != null);
|
||||||
operations.add(DatabaseBatchInteractor.createInsertUserPacket(userPacket));
|
operations.add(DatabaseBatchInteractor.createInsertUserPacket(userPacket));
|
||||||
|
|
||||||
@@ -508,14 +510,13 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
mIndent -= 1;
|
mIndent -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SupportSQLiteDatabase db = databaseBatchInteractor.getDb();
|
SupportSQLiteDatabase db = getWritableDb();
|
||||||
try {
|
try {
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
|
|
||||||
// delete old version of this keyRing (from database only!), which also deletes all keys and userIds on cascade
|
// delete old version of this keyRing (from database only!), which also deletes all keys and userIds on cascade
|
||||||
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(db);
|
getDatabase().getKeyRingsPublicQueries().deleteByMasterKeyId(masterKeyId);
|
||||||
deleteStatement.bind(masterKeyId);
|
int deletedRows = getDatabase().getUtilQueries().selectChanges().executeAsOne().intValue();
|
||||||
int deletedRows = deleteStatement.executeUpdateDelete();
|
|
||||||
|
|
||||||
if (deletedRows > 0) {
|
if (deletedRows > 0) {
|
||||||
log(LogType.MSG_IP_DELETE_OLD_OK);
|
log(LogType.MSG_IP_DELETE_OLD_OK);
|
||||||
@@ -559,9 +560,8 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
}
|
}
|
||||||
autocryptPeerDao.deleteByMasterKeyId(masterKeyId);
|
autocryptPeerDao.deleteByMasterKeyId(masterKeyId);
|
||||||
|
|
||||||
DeleteByMasterKeyId deleteStatement = new DeleteByMasterKeyId(getWritableDb());
|
getDatabase().getKeyRingsPublicQueries().deleteByMasterKeyId(masterKeyId);
|
||||||
deleteStatement.bind(masterKeyId);
|
int deletedRows = getDatabase().getUtilQueries().selectChanges().executeAsOne().intValue();
|
||||||
int deletedRows = deleteStatement.executeUpdateDelete();
|
|
||||||
|
|
||||||
databaseNotifyManager.notifyKeyChange(masterKeyId);
|
databaseNotifyManager.notifyKeyChange(masterKeyId);
|
||||||
|
|
||||||
@@ -631,12 +631,10 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
UpdateHasSecretByMasterKeyId resetStatement =
|
KeysQueries keysQueries = getDatabase().getKeysQueries();
|
||||||
SubKey.createUpdateHasSecretByMasterKeyIdStatement(getWritableDb());
|
UtilQueries utilQueries = getDatabase().getUtilQueries();
|
||||||
resetStatement.bind(masterKeyId, SecretKeyType.GNU_DUMMY);
|
|
||||||
resetStatement.executeUpdateDelete();
|
|
||||||
|
|
||||||
UpdateHasSecretByKeyId updateStatement = SubKey.createUpdateHasSecretByKeyId(getWritableDb());
|
keysQueries.updateHasSecretByMasterKeyId(masterKeyId, SecretKeyType.GNU_DUMMY);
|
||||||
|
|
||||||
// then, mark exactly the keys we have available
|
// then, mark exactly the keys we have available
|
||||||
log(LogType.MSG_IS_IMPORTING_SUBKEYS);
|
log(LogType.MSG_IS_IMPORTING_SUBKEYS);
|
||||||
@@ -644,8 +642,8 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
for (CanonicalizedSecretKey sub : keyRing.secretKeyIterator()) {
|
for (CanonicalizedSecretKey sub : keyRing.secretKeyIterator()) {
|
||||||
long id = sub.getKeyId();
|
long id = sub.getKeyId();
|
||||||
SecretKeyType mode = sub.getSecretKeyTypeSuperExpensive();
|
SecretKeyType mode = sub.getSecretKeyTypeSuperExpensive();
|
||||||
updateStatement.bind(id, mode);
|
keysQueries.updateHasSecretByKeyId(id, mode);
|
||||||
int upd = updateStatement.executeUpdateDelete();
|
int upd = utilQueries.selectChanges().executeAsOne().intValue();
|
||||||
if (upd == 1) {
|
if (upd == 1) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case PASSPHRASE:
|
case PASSPHRASE:
|
||||||
@@ -1013,8 +1011,9 @@ public class KeyWritableRepository extends KeyRepository {
|
|||||||
|
|
||||||
private BatchOp buildCertOperations(long masterKeyId, int rank, WrappedSignature cert, VerificationStatus verificationStatus) {
|
private BatchOp buildCertOperations(long masterKeyId, int rank, WrappedSignature cert, VerificationStatus verificationStatus) {
|
||||||
try {
|
try {
|
||||||
Certification certification = Certification.create(masterKeyId, rank, cert.getKeyId(),
|
long creationUnixTime = cert.getCreationTime().getTime() / 1000;
|
||||||
cert.getSignatureType(), verificationStatus, cert.getCreationTime(), cert.getEncoded());
|
Certs certification = new Certs(masterKeyId, rank, cert.getKeyId(),
|
||||||
|
cert.getSignatureType(), verificationStatus, creationUnixTime, cert.getEncoded());
|
||||||
return DatabaseBatchInteractor.createInsertCertification(certification);
|
return DatabaseBatchInteractor.createInsertCertification(certification);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
|
|||||||
@@ -20,11 +20,7 @@ package org.sufficientlysecure.keychain.daos;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import com.squareup.sqldelight.SqlDelightQuery;
|
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.OverriddenWarningsModel.DeleteByIdentifier;
|
|
||||||
import org.sufficientlysecure.keychain.OverriddenWarningsModel.InsertIdentifier;
|
|
||||||
import org.sufficientlysecure.keychain.model.OverriddenWarning;
|
|
||||||
|
|
||||||
|
|
||||||
public class OverriddenWarningsDao extends AbstractDao {
|
public class OverriddenWarningsDao extends AbstractDao {
|
||||||
@@ -35,25 +31,21 @@ public class OverriddenWarningsDao extends AbstractDao {
|
|||||||
return new OverriddenWarningsDao(database, databaseNotifyManager);
|
return new OverriddenWarningsDao(database, databaseNotifyManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
private OverriddenWarningsDao(KeychainDatabase db, DatabaseNotifyManager databaseNotifyManager) {
|
private OverriddenWarningsDao(KeychainDatabase db,
|
||||||
|
DatabaseNotifyManager databaseNotifyManager) {
|
||||||
super(db, databaseNotifyManager);
|
super(db, databaseNotifyManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isWarningOverridden(String identifier) {
|
public boolean isWarningOverridden(String identifier) {
|
||||||
SqlDelightQuery query = OverriddenWarning.FACTORY.selectCountByIdentifier(identifier);
|
return getDatabase().getOverriddenWarningsQueries().selectCountByIdentifier(identifier)
|
||||||
Long result = mapSingleRow(query, OverriddenWarning.FACTORY.selectCountByIdentifierMapper()::map);
|
.executeAsOne() > 0;
|
||||||
return result != null && result > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void putOverride(String identifier) {
|
public void putOverride(String identifier) {
|
||||||
InsertIdentifier statement = new InsertIdentifier(getWritableDb());
|
getDatabase().getOverriddenWarningsQueries().insertIdentifier(identifier);
|
||||||
statement.bind(identifier);
|
|
||||||
statement.executeInsert();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteOverride(String identifier) {
|
public void deleteOverride(String identifier) {
|
||||||
DeleteByIdentifier statement = new DeleteByIdentifier(getWritableDb());
|
getDatabase().getOverriddenWarningsQueries().deleteByIdentifier(identifier);
|
||||||
statement.bind(identifier);
|
|
||||||
statement.executeInsert();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
package org.sufficientlysecure.keychain.daos;
|
package org.sufficientlysecure.keychain.daos;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
|
||||||
|
|
||||||
import com.squareup.sqldelight.SqlDelightQuery;
|
import com.squareup.sqldelight.Query;
|
||||||
|
import com.squareup.sqldelight.db.SqlCursor;
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket;
|
import org.sufficientlysecure.keychain.UidStatus;
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket.UidStatus;
|
import org.sufficientlysecure.keychain.model.UserId;
|
||||||
|
|
||||||
|
|
||||||
public class UserIdDao extends AbstractDao {
|
public class UserIdDao extends AbstractDao {
|
||||||
@@ -25,20 +28,38 @@ public class UserIdDao extends AbstractDao {
|
|||||||
super(db, databaseNotifyManager);
|
super(db, databaseNotifyManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UidStatus getUidStatusByEmailLike(String emailLike) {
|
public List<UserId> getUserIdsByMasterKeyIds(long... masterKeyIds) {
|
||||||
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdStatusByEmailLike(emailLike);
|
return getDatabase().getUserPacketsQueries()
|
||||||
return mapSingleRow(query, UserPacket.UID_STATUS_MAPPER);
|
.selectUserIdsByMasterKeyId(getLongArrayAsList(masterKeyIds), UserId::create)
|
||||||
|
.executeAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String,UidStatus> getUidStatusByEmail(String... emails) {
|
public UidStatus getUidStatusByEmailLike(String emailLike) {
|
||||||
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdStatusByEmail(emails);
|
return getDatabase().getUserPacketsQueries().selectUserIdStatusByEmailLike(emailLike)
|
||||||
Map<String,UidStatus> result = new HashMap<>();
|
.executeAsOne();
|
||||||
try (Cursor cursor = getReadableDb().query(query)) {
|
}
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
UidStatus item = UserPacket.UID_STATUS_MAPPER.map(cursor);
|
public Map<String, UidStatus> getUidStatusByEmail(String... emails) {
|
||||||
result.put(item.email(), item);
|
Query<UidStatus> q = getDatabase().getUserPacketsQueries()
|
||||||
|
.selectUserIdStatusByEmail(Arrays.asList(emails));
|
||||||
|
Map<String, UidStatus> result = new HashMap<>();
|
||||||
|
try (SqlCursor cursor = q.execute()) {
|
||||||
|
while (cursor.next()) {
|
||||||
|
UidStatus item = q.getMapper().invoke(cursor);
|
||||||
|
result.put(item.getEmail(), item);
|
||||||
}
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// oops
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private List<Long> getLongArrayAsList(long[] longList) {
|
||||||
|
Long[] longs = new Long[longList.length];
|
||||||
|
int i = 0;
|
||||||
|
for (Long aLong : longList) {
|
||||||
|
longs[i++] = aLong;
|
||||||
|
}
|
||||||
|
return Arrays.asList(longs);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,11 +10,11 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Api_apps;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
||||||
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
|
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
|
||||||
import org.sufficientlysecure.keychain.livedata.ApiAppsLiveData.ListedApp;
|
import org.sufficientlysecure.keychain.livedata.ApiAppsLiveData.ListedApp;
|
||||||
import org.sufficientlysecure.keychain.model.ApiApp;
|
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.AsyncTaskLiveData;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.AsyncTaskLiveData;
|
||||||
|
|
||||||
|
|
||||||
@@ -41,18 +41,18 @@ public class ApiAppsLiveData extends AsyncTaskLiveData<List<ListedApp>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void loadRegisteredApps(ArrayList<ListedApp> result) {
|
private void loadRegisteredApps(ArrayList<ListedApp> result) {
|
||||||
List<ApiApp> registeredApiApps = apiAppDao.getAllApiApps();
|
List<Api_apps> registeredApiApps = apiAppDao.getAllApiApps();
|
||||||
|
|
||||||
for (ApiApp apiApp : registeredApiApps) {
|
for (Api_apps apiApp : registeredApiApps) {
|
||||||
ListedApp listedApp;
|
ListedApp listedApp;
|
||||||
try {
|
try {
|
||||||
ApplicationInfo ai = packageManager.getApplicationInfo(apiApp.package_name(), 0);
|
ApplicationInfo ai = packageManager.getApplicationInfo(apiApp.getPackage_name(), 0);
|
||||||
CharSequence applicationLabel = packageManager.getApplicationLabel(ai);
|
CharSequence applicationLabel = packageManager.getApplicationLabel(ai);
|
||||||
Drawable applicationIcon = packageManager.getApplicationIcon(ai);
|
Drawable applicationIcon = packageManager.getApplicationIcon(ai);
|
||||||
|
|
||||||
listedApp = new ListedApp(apiApp.package_name(), true, true, applicationLabel, applicationIcon, null);
|
listedApp = new ListedApp(apiApp.getPackage_name(), true, true, applicationLabel, applicationIcon, null);
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
listedApp = new ListedApp(apiApp.package_name(), false, true, apiApp.package_name(), null, null);
|
listedApp = new ListedApp(apiApp.getPackage_name(), false, true, apiApp.getPackage_name(), null, null);
|
||||||
}
|
}
|
||||||
result.add(listedApp);
|
result.add(listedApp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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 {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,9 +4,7 @@ package org.sufficientlysecure.keychain.model;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.squareup.sqldelight.ColumnAdapter;
|
import com.squareup.sqldelight.ColumnAdapter;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||||
|
|
||||||
@@ -15,7 +13,7 @@ public final class CustomColumnAdapters {
|
|||||||
|
|
||||||
private CustomColumnAdapters() { }
|
private CustomColumnAdapters() { }
|
||||||
|
|
||||||
static final ColumnAdapter<Date,Long> DATE_ADAPTER = new ColumnAdapter<Date,Long>() {
|
public static final ColumnAdapter<Date,Long> DATE_ADAPTER = new ColumnAdapter<Date,Long>() {
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Date decode(Long databaseValue) {
|
public Date decode(Long databaseValue) {
|
||||||
@@ -29,7 +27,7 @@ public final class CustomColumnAdapters {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static final ColumnAdapter<GossipOrigin,Long> GOSSIP_ORIGIN_ADAPTER = new ColumnAdapter<GossipOrigin,Long>() {
|
public static final ColumnAdapter<GossipOrigin,Long> GOSSIP_ORIGIN_ADAPTER = new ColumnAdapter<GossipOrigin,Long>() {
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public GossipOrigin decode(Long databaseValue) {
|
public GossipOrigin decode(Long databaseValue) {
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.sufficientlysecure.keychain.model;
|
||||||
|
|
||||||
|
public enum GossipOrigin {
|
||||||
|
GOSSIP_HEADER, SIGNATURE, DEDUP
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -40,7 +40,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ package org.sufficientlysecure.keychain.operations;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.RevokeResult;
|
import org.sufficientlysecure.keychain.operations.results.RevokeResult;
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import org.openintents.openpgp.OpenPgpSignatureResult;
|
|||||||
import org.openintents.openpgp.OpenPgpSignatureResult.SenderStatusResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult.SenderStatusResult;
|
||||||
import org.openintents.openpgp.util.OpenPgpUtils;
|
import org.openintents.openpgp.util.OpenPgpUtils;
|
||||||
import org.openintents.openpgp.util.OpenPgpUtils.UserId;
|
import org.openintents.openpgp.util.OpenPgpUtils.UserId;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,20 +8,20 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import org.openintents.openpgp.AutocryptPeerUpdate;
|
import org.openintents.openpgp.AutocryptPeerUpdate;
|
||||||
import org.openintents.openpgp.AutocryptPeerUpdate.PreferEncrypt;
|
import org.openintents.openpgp.AutocryptPeerUpdate.PreferEncrypt;
|
||||||
|
import org.sufficientlysecure.keychain.Autocrypt_peers;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer;
|
import org.sufficientlysecure.keychain.SelectAutocryptKeyStatus;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer.AutocryptKeyStatus;
|
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
|
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
||||||
|
import org.sufficientlysecure.keychain.model.GossipOrigin;
|
||||||
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
|
|
||||||
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
||||||
@@ -48,17 +48,17 @@ public class AutocryptInteractor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateAutocryptPeerState(String autocryptPeerId, AutocryptPeerUpdate autocryptPeerUpdate) {
|
void updateAutocryptPeerState(String autocryptPeerId, AutocryptPeerUpdate autocryptPeerUpdate) {
|
||||||
AutocryptPeer currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId);
|
Autocrypt_peers currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId);
|
||||||
Date effectiveDate = autocryptPeerUpdate.getEffectiveDate();
|
Date effectiveDate = autocryptPeerUpdate.getEffectiveDate();
|
||||||
|
|
||||||
// 1. If the message’s effective date is older than the peers[from-addr].autocrypt_timestamp value, then no changes are required, and the update process terminates.
|
// 1. If the message’s effective date is older than the peers[from-addr].autocrypt_timestamp value, then no changes are required, and the update process terminates.
|
||||||
Date lastSeenKey = currentAutocryptPeer != null ? currentAutocryptPeer.last_seen_key() : null;
|
Date lastSeenKey = currentAutocryptPeer != null ? currentAutocryptPeer.getLast_seen_key() : null;
|
||||||
if (lastSeenKey != null && effectiveDate.compareTo(lastSeenKey) <= 0) {
|
if (lastSeenKey != null && effectiveDate.compareTo(lastSeenKey) <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. If the message’s effective date is more recent than peers[from-addr].last_seen then set peers[from-addr].last_seen to the message’s effective date.
|
// 2. If the message’s effective date is more recent than peers[from-addr].last_seen then set peers[from-addr].last_seen to the message’s effective date.
|
||||||
Date lastSeen = currentAutocryptPeer != null ? currentAutocryptPeer.last_seen() : null;
|
Date lastSeen = currentAutocryptPeer != null ? currentAutocryptPeer.getLast_seen() : null;
|
||||||
if (lastSeen == null || effectiveDate.after(lastSeen)) {
|
if (lastSeen == null || effectiveDate.after(lastSeen)) {
|
||||||
autocryptPeerDao.insertOrUpdateLastSeen(packageName, autocryptPeerId, effectiveDate);
|
autocryptPeerDao.insertOrUpdateLastSeen(packageName, autocryptPeerId, effectiveDate);
|
||||||
}
|
}
|
||||||
@@ -83,14 +83,14 @@ public class AutocryptInteractor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateAutocryptPeerGossipState(String autocryptPeerId, AutocryptPeerUpdate autocryptPeerUpdate) {
|
void updateAutocryptPeerGossipState(String autocryptPeerId, AutocryptPeerUpdate autocryptPeerUpdate) {
|
||||||
AutocryptPeer currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId);
|
Autocrypt_peers currentAutocryptPeer = autocryptPeerDao.getAutocryptPeer(packageName, autocryptPeerId);
|
||||||
Date effectiveDate = autocryptPeerUpdate.getEffectiveDate();
|
Date effectiveDate = autocryptPeerUpdate.getEffectiveDate();
|
||||||
|
|
||||||
// 1. If gossip-addr does not match any recipient in the mail’s To or Cc header, the update process terminates (i.e., header is ignored).
|
// 1. If gossip-addr does not match any recipient in the mail’s To or Cc header, the update process terminates (i.e., header is ignored).
|
||||||
// -> This should be taken care of in the mail client that sends us this data!
|
// -> This should be taken care of in the mail client that sends us this data!
|
||||||
|
|
||||||
// 2. If peers[gossip-addr].gossip_timestamp is more recent than the message’s effective date, then the update process terminates.
|
// 2. If peers[gossip-addr].gossip_timestamp is more recent than the message’s effective date, then the update process terminates.
|
||||||
Date lastSeenGossip = currentAutocryptPeer != null ? currentAutocryptPeer.gossip_last_seen_key() : null;
|
Date lastSeenGossip = currentAutocryptPeer != null ? currentAutocryptPeer.getGossip_last_seen_key() : null;
|
||||||
if (lastSeenGossip != null && lastSeenGossip.after(effectiveDate)) {
|
if (lastSeenGossip != null && lastSeenGossip.after(effectiveDate)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -150,7 +150,7 @@ public class AutocryptInteractor {
|
|||||||
public Map<String,AutocryptRecommendationResult> determineAutocryptRecommendations(String... autocryptIds) {
|
public Map<String,AutocryptRecommendationResult> determineAutocryptRecommendations(String... autocryptIds) {
|
||||||
Map<String,AutocryptRecommendationResult> result = new HashMap<>(autocryptIds.length);
|
Map<String,AutocryptRecommendationResult> result = new HashMap<>(autocryptIds.length);
|
||||||
|
|
||||||
for (AutocryptKeyStatus autocryptKeyStatus : autocryptPeerDao.getAutocryptKeyStatus(packageName, autocryptIds)) {
|
for (SelectAutocryptKeyStatus autocryptKeyStatus : autocryptPeerDao.getAutocryptKeyStatus(packageName, autocryptIds)) {
|
||||||
AutocryptRecommendationResult peerResult = determineAutocryptRecommendation(autocryptKeyStatus);
|
AutocryptRecommendationResult peerResult = determineAutocryptRecommendation(autocryptKeyStatus);
|
||||||
result.put(peerResult.peerId, peerResult);
|
result.put(peerResult.peerId, peerResult);
|
||||||
}
|
}
|
||||||
@@ -161,58 +161,60 @@ public class AutocryptInteractor {
|
|||||||
/** Determines Autocrypt "ui-recommendation", according to spec.
|
/** Determines Autocrypt "ui-recommendation", according to spec.
|
||||||
* See https://autocrypt.org/level1.html#recommendations-for-single-recipient-messages
|
* See https://autocrypt.org/level1.html#recommendations-for-single-recipient-messages
|
||||||
*/
|
*/
|
||||||
private AutocryptRecommendationResult determineAutocryptRecommendation(AutocryptKeyStatus autocryptKeyStatus) {
|
private AutocryptRecommendationResult determineAutocryptRecommendation(
|
||||||
|
SelectAutocryptKeyStatus autocryptKeyStatus) {
|
||||||
AutocryptRecommendationResult keyRecommendation = determineAutocryptKeyRecommendation(autocryptKeyStatus);
|
AutocryptRecommendationResult keyRecommendation = determineAutocryptKeyRecommendation(autocryptKeyStatus);
|
||||||
if (keyRecommendation != null) return keyRecommendation;
|
if (keyRecommendation != null) return keyRecommendation;
|
||||||
|
|
||||||
AutocryptRecommendationResult gossipRecommendation = determineAutocryptGossipRecommendation(autocryptKeyStatus);
|
AutocryptRecommendationResult gossipRecommendation = determineAutocryptGossipRecommendation(autocryptKeyStatus);
|
||||||
if (gossipRecommendation != null) return gossipRecommendation;
|
if (gossipRecommendation != null) return gossipRecommendation;
|
||||||
|
|
||||||
return new AutocryptRecommendationResult(autocryptKeyStatus.autocryptPeer().identifier(), AutocryptState.DISABLE, null, false);
|
return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.DISABLE, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private AutocryptRecommendationResult determineAutocryptKeyRecommendation(AutocryptKeyStatus autocryptKeyStatus) {
|
private AutocryptRecommendationResult determineAutocryptKeyRecommendation(
|
||||||
AutocryptPeer autocryptPeer = autocryptKeyStatus.autocryptPeer();
|
SelectAutocryptKeyStatus autocryptKeyStatus) {
|
||||||
|
Long masterKeyId = autocryptKeyStatus.getMaster_key_id();
|
||||||
Long masterKeyId = autocryptPeer.master_key_id();
|
|
||||||
boolean hasKey = masterKeyId != null;
|
boolean hasKey = masterKeyId != null;
|
||||||
boolean isRevoked = autocryptKeyStatus.isKeyRevoked();
|
boolean isRevoked = Boolean.TRUE.equals(autocryptKeyStatus.getKey_is_revoked());
|
||||||
boolean isExpired = autocryptKeyStatus.isKeyExpired();
|
boolean isExpired = autocryptKeyStatus.getKey_is_expired_int() != 0;
|
||||||
if (!hasKey || isRevoked || isExpired) {
|
if (!hasKey || isRevoked || isExpired) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Date lastSeen = autocryptPeer.last_seen();
|
Date lastSeen = autocryptKeyStatus.getLast_seen();
|
||||||
Date lastSeenKey = autocryptPeer.last_seen_key();
|
Date lastSeenKey = autocryptKeyStatus.getLast_seen_key();
|
||||||
boolean isVerified = autocryptKeyStatus.isKeyVerified();
|
boolean isVerified = autocryptKeyStatus.getKey_is_verified();
|
||||||
boolean isLastSeenOlderThanDiscourageTimespan = lastSeen != null && lastSeenKey != null &&
|
boolean isLastSeenOlderThanDiscourageTimespan = lastSeen != null && lastSeenKey != null &&
|
||||||
lastSeenKey.getTime() < (lastSeen.getTime() - AUTOCRYPT_DISCOURAGE_THRESHOLD_MILLIS);
|
lastSeenKey.getTime() < (lastSeen.getTime() - AUTOCRYPT_DISCOURAGE_THRESHOLD_MILLIS);
|
||||||
if (isLastSeenOlderThanDiscourageTimespan) {
|
if (isLastSeenOlderThanDiscourageTimespan) {
|
||||||
return new AutocryptRecommendationResult(autocryptPeer.identifier(), AutocryptState.DISCOURAGED_OLD, masterKeyId, isVerified);
|
return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.DISCOURAGED_OLD, masterKeyId, isVerified);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isMutual = autocryptPeer.is_mutual();
|
boolean isMutual = autocryptKeyStatus.is_mutual();
|
||||||
if (isMutual) {
|
if (isMutual) {
|
||||||
return new AutocryptRecommendationResult(autocryptPeer.identifier(), AutocryptState.MUTUAL, masterKeyId, isVerified);
|
return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.MUTUAL, masterKeyId, isVerified);
|
||||||
} else {
|
} else {
|
||||||
return new AutocryptRecommendationResult(autocryptPeer.identifier(), AutocryptState.AVAILABLE, masterKeyId, isVerified);
|
return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.AVAILABLE, masterKeyId, isVerified);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private AutocryptRecommendationResult determineAutocryptGossipRecommendation(AutocryptKeyStatus autocryptKeyStatus) {
|
private AutocryptRecommendationResult determineAutocryptGossipRecommendation(
|
||||||
boolean gossipHasKey = autocryptKeyStatus.hasGossipKey();
|
SelectAutocryptKeyStatus autocryptKeyStatus) {
|
||||||
boolean gossipIsRevoked = autocryptKeyStatus.isGossipKeyRevoked();
|
boolean gossipHasKey = autocryptKeyStatus.getGossip_master_key_id() != null;
|
||||||
boolean gossipIsExpired = autocryptKeyStatus.isGossipKeyExpired();
|
boolean gossipIsRevoked =
|
||||||
boolean isVerified = autocryptKeyStatus.isGossipKeyVerified();
|
Boolean.TRUE.equals(autocryptKeyStatus.getGossip_key_is_revoked());
|
||||||
|
boolean gossipIsExpired = autocryptKeyStatus.getGossip_key_is_expired_int() != 0;
|
||||||
|
boolean isVerified = autocryptKeyStatus.getGossip_key_is_verified();
|
||||||
|
|
||||||
if (!gossipHasKey || gossipIsRevoked || gossipIsExpired) {
|
if (!gossipHasKey || gossipIsRevoked || gossipIsExpired) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Long masterKeyId = autocryptKeyStatus.autocryptPeer().gossip_master_key_id();
|
Long masterKeyId = autocryptKeyStatus.getGossip_master_key_id();
|
||||||
return new AutocryptRecommendationResult(autocryptKeyStatus.autocryptPeer().identifier(), AutocryptState.DISCOURAGED_GOSSIP, masterKeyId, isVerified);
|
return new AutocryptRecommendationResult(autocryptKeyStatus.getIdentifier(), AutocryptState.DISCOURAGED_GOSSIP, masterKeyId, isVerified);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateKeyGossipFromSignature(String autocryptId, Date effectiveDate, long masterKeyId) {
|
public void updateKeyGossipFromSignature(String autocryptId, Date effectiveDate, long masterKeyId) {
|
||||||
|
|||||||
@@ -31,14 +31,15 @@ import android.content.UriMatcher;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.MatrixCursor;
|
import android.database.MatrixCursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import org.sufficientlysecure.keychain.BuildConfig;
|
import org.sufficientlysecure.keychain.BuildConfig;
|
||||||
|
import org.sufficientlysecure.keychain.UidStatus;
|
||||||
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
||||||
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
|
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
|
||||||
import org.sufficientlysecure.keychain.daos.UserIdDao;
|
import org.sufficientlysecure.keychain.daos.UserIdDao;
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket.UidStatus;
|
import org.sufficientlysecure.keychain.model.CustomColumnAdapters;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
|
import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptStatus;
|
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.AutocryptStatus;
|
||||||
@@ -65,7 +66,8 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
|
|
||||||
matcher.addURI(authority, KeychainExternalContract.BASE_EMAIL_STATUS, EMAIL_STATUS);
|
matcher.addURI(authority, KeychainExternalContract.BASE_EMAIL_STATUS, EMAIL_STATUS);
|
||||||
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS, AUTOCRYPT_STATUS);
|
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS, AUTOCRYPT_STATUS);
|
||||||
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS + "/*", AUTOCRYPT_STATUS_INTERNAL);
|
matcher.addURI(authority, KeychainExternalContract.BASE_AUTOCRYPT_STATUS + "/*",
|
||||||
|
AUTOCRYPT_STATUS_INTERNAL);
|
||||||
|
|
||||||
return matcher;
|
return matcher;
|
||||||
}
|
}
|
||||||
@@ -84,8 +86,9 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs,
|
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
|
||||||
String sortOrder) {
|
String[] selectionArgs,
|
||||||
|
String sortOrder) {
|
||||||
Timber.v("query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")");
|
Timber.v("query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")");
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
@@ -97,7 +100,8 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
int match = uriMatcher.match(uri);
|
int match = uriMatcher.match(uri);
|
||||||
switch (match) {
|
switch (match) {
|
||||||
case EMAIL_STATUS: {
|
case EMAIL_STATUS: {
|
||||||
Toast.makeText(context, "This API is no longer supported by OpenKeychain!", Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, "This API is no longer supported by OpenKeychain!",
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
return new MatrixCursor(projection);
|
return new MatrixCursor(projection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,12 +111,14 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// override package name to use any external
|
// override package name to use any external
|
||||||
callingPackageName = uri.getLastPathSegment();
|
callingPackageName = uri.getLastPathSegment();
|
||||||
|
|
||||||
case AUTOCRYPT_STATUS: {
|
case AUTOCRYPT_STATUS: {
|
||||||
boolean callerIsAllowed = (match == AUTOCRYPT_STATUS_INTERNAL) || apiPermissionHelper.isAllowedIgnoreErrors();
|
boolean callerIsAllowed = (match == AUTOCRYPT_STATUS_INTERNAL) ||
|
||||||
|
apiPermissionHelper.isAllowedIgnoreErrors();
|
||||||
if (!callerIsAllowed) {
|
if (!callerIsAllowed) {
|
||||||
throw new AccessControlException("An application must register before use of KeychainExternalProvider!");
|
throw new AccessControlException(
|
||||||
|
"An application must register before use of KeychainExternalProvider!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projection == null) {
|
if (projection == null) {
|
||||||
@@ -120,25 +126,32 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<String> plist = Arrays.asList(projection);
|
List<String> plist = Arrays.asList(projection);
|
||||||
boolean isWildcardSelector = selectionArgs.length == 1 && selectionArgs[0].contains("%");
|
boolean isWildcardSelector =
|
||||||
|
selectionArgs.length == 1 && selectionArgs[0].contains("%");
|
||||||
boolean queriesUidResult = plist.contains(AutocryptStatus.UID_KEY_STATUS) ||
|
boolean queriesUidResult = plist.contains(AutocryptStatus.UID_KEY_STATUS) ||
|
||||||
plist.contains(AutocryptStatus.UID_ADDRESS) ||
|
plist.contains(AutocryptStatus.UID_ADDRESS) ||
|
||||||
plist.contains(AutocryptStatus.UID_MASTER_KEY_ID) ||
|
plist.contains(AutocryptStatus.UID_MASTER_KEY_ID) ||
|
||||||
plist.contains(AutocryptStatus.UID_CANDIDATES);
|
plist.contains(AutocryptStatus.UID_CANDIDATES);
|
||||||
boolean queriesAutocryptResult = plist.contains(AutocryptStatus.AUTOCRYPT_PEER_STATE) ||
|
boolean queriesAutocryptResult =
|
||||||
plist.contains(AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID) ||
|
plist.contains(AutocryptStatus.AUTOCRYPT_PEER_STATE) ||
|
||||||
plist.contains(AutocryptStatus.AUTOCRYPT_KEY_STATUS);
|
plist.contains(AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID) ||
|
||||||
|
plist.contains(AutocryptStatus.AUTOCRYPT_KEY_STATUS);
|
||||||
if (isWildcardSelector && queriesAutocryptResult) {
|
if (isWildcardSelector && queriesAutocryptResult) {
|
||||||
throw new UnsupportedOperationException("Cannot wildcard-query autocrypt results!");
|
throw new UnsupportedOperationException(
|
||||||
|
"Cannot wildcard-query autocrypt results!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, UidStatus> uidStatuses = queriesUidResult ?
|
Map<String, UidStatus> uidStatuses = queriesUidResult ?
|
||||||
loadUidStatusMap(selectionArgs, isWildcardSelector) : Collections.emptyMap();
|
loadUidStatusMap(selectionArgs, isWildcardSelector) :
|
||||||
Map<String, AutocryptRecommendationResult> autocryptStates = queriesAutocryptResult ?
|
Collections.emptyMap();
|
||||||
loadAutocryptRecommendationMap(selectionArgs, callingPackageName) : Collections.emptyMap();
|
Map<String, AutocryptRecommendationResult> autocryptStates =
|
||||||
|
queriesAutocryptResult ?
|
||||||
|
loadAutocryptRecommendationMap(selectionArgs, callingPackageName) :
|
||||||
|
Collections.emptyMap();
|
||||||
|
|
||||||
MatrixCursor cursor =
|
MatrixCursor cursor =
|
||||||
mapResultsToProjectedMatrixCursor(projection, selectionArgs, uidStatuses, autocryptStates);
|
mapResultsToProjectedMatrixCursor(projection, selectionArgs, uidStatuses,
|
||||||
|
autocryptStates);
|
||||||
|
|
||||||
uri = DatabaseNotifyManager.getNotifyUriAllKeys();
|
uri = DatabaseNotifyManager.getNotifyUriAllKeys();
|
||||||
cursor.setNotificationUri(context.getContentResolver(), uri);
|
cursor.setNotificationUri(context.getContentResolver(), uri);
|
||||||
@@ -153,8 +166,10 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private MatrixCursor mapResultsToProjectedMatrixCursor(String[] projection, String[] selectionArgs,
|
private MatrixCursor mapResultsToProjectedMatrixCursor(String[] projection,
|
||||||
Map<String, UidStatus> uidStatuses, Map<String, AutocryptRecommendationResult> autocryptStates) {
|
String[] selectionArgs,
|
||||||
|
Map<String, UidStatus> uidStatuses,
|
||||||
|
Map<String, AutocryptRecommendationResult> autocryptStates) {
|
||||||
MatrixCursor cursor = new MatrixCursor(projection);
|
MatrixCursor cursor = new MatrixCursor(projection);
|
||||||
for (String selectionArg : selectionArgs) {
|
for (String selectionArg : selectionArgs) {
|
||||||
AutocryptRecommendationResult autocryptResult = autocryptStates.get(selectionArg);
|
AutocryptRecommendationResult autocryptResult = autocryptStates.get(selectionArg);
|
||||||
@@ -162,7 +177,8 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
|
|
||||||
Object[] row = new Object[projection.length];
|
Object[] row = new Object[projection.length];
|
||||||
for (int i = 0; i < projection.length; i++) {
|
for (int i = 0; i < projection.length; i++) {
|
||||||
if (AutocryptStatus.ADDRESS.equals(projection[i]) || AutocryptStatus._ID.equals(projection[i])) {
|
if (AutocryptStatus.ADDRESS.equals(projection[i]) ||
|
||||||
|
AutocryptStatus._ID.equals(projection[i])) {
|
||||||
row[i] = selectionArg;
|
row[i] = selectionArg;
|
||||||
} else {
|
} else {
|
||||||
row[i] = columnNameToRowContent(projection[i], autocryptResult, uidStatus);
|
row[i] = columnNameToRowContent(projection[i], autocryptResult, uidStatus);
|
||||||
@@ -180,7 +196,8 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
if (uidStatus == null) {
|
if (uidStatus == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return uidStatus.keyStatus() == VerificationStatus.VERIFIED_SECRET ?
|
return CustomColumnAdapters.VERIFICATON_STATUS_ADAPTER.decode(
|
||||||
|
uidStatus.getKey_status_int()) == VerificationStatus.VERIFIED_SECRET ?
|
||||||
KeychainExternalContract.KEY_STATUS_VERIFIED :
|
KeychainExternalContract.KEY_STATUS_VERIFIED :
|
||||||
KeychainExternalContract.KEY_STATUS_UNVERIFIED;
|
KeychainExternalContract.KEY_STATUS_UNVERIFIED;
|
||||||
}
|
}
|
||||||
@@ -188,19 +205,19 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
if (uidStatus == null) {
|
if (uidStatus == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return uidStatus.user_id();
|
return uidStatus.getUser_id();
|
||||||
|
|
||||||
case AutocryptStatus.UID_MASTER_KEY_ID:
|
case AutocryptStatus.UID_MASTER_KEY_ID:
|
||||||
if (uidStatus == null) {
|
if (uidStatus == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return uidStatus.master_key_id();
|
return uidStatus.getMaster_key_id();
|
||||||
|
|
||||||
case AutocryptStatus.UID_CANDIDATES:
|
case AutocryptStatus.UID_CANDIDATES:
|
||||||
if (uidStatus == null) {
|
if (uidStatus == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return uidStatus.candidates();
|
return uidStatus.getCandidates();
|
||||||
|
|
||||||
case AutocryptStatus.AUTOCRYPT_PEER_STATE:
|
case AutocryptStatus.AUTOCRYPT_PEER_STATE:
|
||||||
if (autocryptResult == null) {
|
if (autocryptResult == null) {
|
||||||
@@ -213,7 +230,8 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return autocryptResult.isVerified ?
|
return autocryptResult.isVerified ?
|
||||||
KeychainExternalContract.KEY_STATUS_VERIFIED : KeychainExternalContract.KEY_STATUS_UNVERIFIED;
|
KeychainExternalContract.KEY_STATUS_VERIFIED :
|
||||||
|
KeychainExternalContract.KEY_STATUS_UNVERIFIED;
|
||||||
|
|
||||||
case AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID:
|
case AutocryptStatus.AUTOCRYPT_MASTER_KEY_ID:
|
||||||
if (autocryptResult == null) {
|
if (autocryptResult == null) {
|
||||||
@@ -226,10 +244,12 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, UidStatus> loadUidStatusMap(String[] selectionArgs, boolean isWildcardSelector) {
|
private Map<String, org.sufficientlysecure.keychain.UidStatus> loadUidStatusMap(
|
||||||
|
String[] selectionArgs, boolean isWildcardSelector) {
|
||||||
UserIdDao userIdDao = UserIdDao.getInstance(getContext());
|
UserIdDao userIdDao = UserIdDao.getInstance(getContext());
|
||||||
if (isWildcardSelector) {
|
if (isWildcardSelector) {
|
||||||
UidStatus uidStatus = userIdDao.getUidStatusByEmailLike(selectionArgs[0]);
|
org.sufficientlysecure.keychain.UidStatus uidStatus =
|
||||||
|
userIdDao.getUidStatusByEmailLike(selectionArgs[0]);
|
||||||
return Collections.singletonMap(selectionArgs[0], uidStatus);
|
return Collections.singletonMap(selectionArgs[0], uidStatus);
|
||||||
} else {
|
} else {
|
||||||
return userIdDao.getUidStatusByEmail(selectionArgs);
|
return userIdDao.getUidStatusByEmail(selectionArgs);
|
||||||
@@ -238,17 +258,23 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
|
|
||||||
private Map<String, AutocryptRecommendationResult> loadAutocryptRecommendationMap(
|
private Map<String, AutocryptRecommendationResult> loadAutocryptRecommendationMap(
|
||||||
String[] selectionArgs, String callingPackageName) {
|
String[] selectionArgs, String callingPackageName) {
|
||||||
AutocryptInteractor autocryptInteractor = AutocryptInteractor.getInstance(getContext(), callingPackageName);
|
AutocryptInteractor autocryptInteractor =
|
||||||
|
AutocryptInteractor.getInstance(getContext(), callingPackageName);
|
||||||
return autocryptInteractor.determineAutocryptRecommendations(selectionArgs);
|
return autocryptInteractor.determineAutocryptRecommendations(selectionArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPeerStateValue(AutocryptState autocryptState) {
|
private int getPeerStateValue(AutocryptState autocryptState) {
|
||||||
switch (autocryptState) {
|
switch (autocryptState) {
|
||||||
case DISABLE: return AutocryptStatus.AUTOCRYPT_PEER_DISABLED;
|
case DISABLE:
|
||||||
case DISCOURAGED_OLD: return AutocryptStatus.AUTOCRYPT_PEER_DISCOURAGED_OLD;
|
return AutocryptStatus.AUTOCRYPT_PEER_DISABLED;
|
||||||
case DISCOURAGED_GOSSIP: return AutocryptStatus.AUTOCRYPT_PEER_GOSSIP;
|
case DISCOURAGED_OLD:
|
||||||
case AVAILABLE: return AutocryptStatus.AUTOCRYPT_PEER_AVAILABLE;
|
return AutocryptStatus.AUTOCRYPT_PEER_DISCOURAGED_OLD;
|
||||||
case MUTUAL: return AutocryptStatus.AUTOCRYPT_PEER_MUTUAL;
|
case DISCOURAGED_GOSSIP:
|
||||||
|
return AutocryptStatus.AUTOCRYPT_PEER_GOSSIP;
|
||||||
|
case AVAILABLE:
|
||||||
|
return AutocryptStatus.AUTOCRYPT_PEER_AVAILABLE;
|
||||||
|
case MUTUAL:
|
||||||
|
return AutocryptStatus.AUTOCRYPT_PEER_MUTUAL;
|
||||||
}
|
}
|
||||||
throw new IllegalStateException("Unhandled case!");
|
throw new IllegalStateException("Unhandled case!");
|
||||||
}
|
}
|
||||||
@@ -269,7 +295,8 @@ public class KeychainExternalProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
public int update(@NonNull Uri uri, ContentValues values, String selection,
|
||||||
|
String[] selectionArgs) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
|
|||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
||||||
import org.sufficientlysecure.keychain.daos.OverriddenWarningsDao;
|
import org.sufficientlysecure.keychain.daos.OverriddenWarningsDao;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.BackupOperation;
|
import org.sufficientlysecure.keychain.operations.BackupOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
|
||||||
import org.sufficientlysecure.keychain.pgp.SshPublicKey;
|
import org.sufficientlysecure.keychain.pgp.SshPublicKey;
|
||||||
|
|||||||
@@ -27,17 +27,17 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.fragment.app.FragmentManager;
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
|
import org.sufficientlysecure.keychain.Api_apps;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.ApiApp;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
|
||||||
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.AdvancedAppSettingsDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.AdvancedAppSettingsDialogFragment;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
@@ -53,7 +53,7 @@ public class AppSettingsActivity extends BaseActivity {
|
|||||||
|
|
||||||
|
|
||||||
// model
|
// model
|
||||||
ApiApp mApiApp;
|
Api_apps mApiApp;
|
||||||
private ApiAppDao apiAppDao;
|
private ApiAppDao apiAppDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -140,7 +140,7 @@ public class AppSettingsActivity extends BaseActivity {
|
|||||||
// advanced info: package certificate SHA-256
|
// advanced info: package certificate SHA-256
|
||||||
try {
|
try {
|
||||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||||
md.update(mApiApp.package_signature());
|
md.update(mApiApp.getPackage_signature());
|
||||||
byte[] digest = md.digest();
|
byte[] digest = md.digest();
|
||||||
certificate = new String(Hex.encode(digest));
|
certificate = new String(Hex.encode(digest));
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
@@ -148,7 +148,7 @@ public class AppSettingsActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AdvancedAppSettingsDialogFragment dialogFragment =
|
AdvancedAppSettingsDialogFragment dialogFragment =
|
||||||
AdvancedAppSettingsDialogFragment.newInstance(mApiApp.package_name(), certificate);
|
AdvancedAppSettingsDialogFragment.newInstance(mApiApp.getPackage_name(), certificate);
|
||||||
|
|
||||||
dialogFragment.show(getSupportFragmentManager(), "advancedDialog");
|
dialogFragment.show(getSupportFragmentManager(), "advancedDialog");
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ public class AppSettingsActivity extends BaseActivity {
|
|||||||
Intent i;
|
Intent i;
|
||||||
PackageManager manager = getPackageManager();
|
PackageManager manager = getPackageManager();
|
||||||
try {
|
try {
|
||||||
i = manager.getLaunchIntentForPackage(mApiApp.package_name());
|
i = manager.getLaunchIntentForPackage(mApiApp.getPackage_name());
|
||||||
if (i == null)
|
if (i == null)
|
||||||
throw new PackageManager.NameNotFoundException();
|
throw new PackageManager.NameNotFoundException();
|
||||||
// start like the Android launcher would do
|
// start like the Android launcher would do
|
||||||
@@ -177,13 +177,13 @@ public class AppSettingsActivity extends BaseActivity {
|
|||||||
Drawable appIcon = null;
|
Drawable appIcon = null;
|
||||||
PackageManager pm = getApplicationContext().getPackageManager();
|
PackageManager pm = getApplicationContext().getPackageManager();
|
||||||
try {
|
try {
|
||||||
ApplicationInfo ai = pm.getApplicationInfo(mApiApp.package_name(), 0);
|
ApplicationInfo ai = pm.getApplicationInfo(mApiApp.getPackage_name(), 0);
|
||||||
|
|
||||||
appName = (String) pm.getApplicationLabel(ai);
|
appName = (String) pm.getApplicationLabel(ai);
|
||||||
appIcon = pm.getApplicationIcon(ai);
|
appIcon = pm.getApplicationIcon(ai);
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
// fallback
|
// fallback
|
||||||
appName = mApiApp.package_name();
|
appName = mApiApp.getPackage_name();
|
||||||
}
|
}
|
||||||
mAppNameView.setText(appName);
|
mAppNameView.setText(appName);
|
||||||
mAppIconView.setImageDrawable(appIcon);
|
mAppIconView.setImageDrawable(appIcon);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import android.os.Bundle;
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import android.content.pm.PackageManager;
|
|||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Api_apps;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.ApiApp;
|
|
||||||
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ class RemoteRegisterPresenter {
|
|||||||
|
|
||||||
private RemoteRegisterView view;
|
private RemoteRegisterView view;
|
||||||
private Intent resultData;
|
private Intent resultData;
|
||||||
private ApiApp apiApp;
|
private Api_apps apiApp;
|
||||||
|
|
||||||
|
|
||||||
RemoteRegisterPresenter(Context context) {
|
RemoteRegisterPresenter(Context context) {
|
||||||
@@ -54,7 +54,7 @@ class RemoteRegisterPresenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setupFromIntentData(Intent resultData, String packageName, byte[] packageSignature) {
|
void setupFromIntentData(Intent resultData, String packageName, byte[] packageSignature) {
|
||||||
this.apiApp = ApiApp.create(packageName, packageSignature);
|
this.apiApp = new Api_apps(0L, packageName, packageSignature);
|
||||||
this.resultData = resultData;
|
this.resultData = resultData;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import android.graphics.drawable.Drawable;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.base.RecyclerFragment;
|
import org.sufficientlysecure.keychain.ui.base.RecyclerFragment;
|
||||||
|
|||||||
@@ -21,24 +21,23 @@ package org.sufficientlysecure.keychain.remote.ui;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import androidx.lifecycle.ViewModelProviders;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData;
|
||||||
|
import androidx.lifecycle.ViewModelProviders;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.openintents.openpgp.util.OpenPgpUtils;
|
import org.openintents.openpgp.util.OpenPgpUtils;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.ApiApp;
|
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
|
||||||
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity;
|
import org.sufficientlysecure.keychain.ui.CreateKeyActivity;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.base.RecyclerFragment;
|
import org.sufficientlysecure.keychain.ui.base.RecyclerFragment;
|
||||||
@@ -117,7 +116,7 @@ public class SelectSignKeyIdListFragment extends RecyclerFragment<KeyChoiceAdapt
|
|||||||
GenericViewModel viewModel = ViewModelProviders.of(this).get(GenericViewModel.class);
|
GenericViewModel viewModel = ViewModelProviders.of(this).get(GenericViewModel.class);
|
||||||
LiveData<List<UnifiedKeyInfo>> liveData = viewModel.getGenericLiveData(
|
LiveData<List<UnifiedKeyInfo>> liveData = viewModel.getGenericLiveData(
|
||||||
requireContext(), keyRepository::getAllUnifiedKeyInfoWithSecret);
|
requireContext(), keyRepository::getAllUnifiedKeyInfoWithSecret);
|
||||||
liveData.observe(this, this::onLoadUnifiedKeyData);
|
liveData.observe(getViewLifecycleOwner(), this::onLoadUnifiedKeyData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onLoadUnifiedKeyData(List<UnifiedKeyInfo> data) {
|
public void onLoadUnifiedKeyData(List<UnifiedKeyInfo> data) {
|
||||||
@@ -155,8 +154,7 @@ public class SelectSignKeyIdListFragment extends RecyclerFragment<KeyChoiceAdapt
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onSelectKeyItemClicked(UnifiedKeyInfo keyInfo) {
|
private void onSelectKeyItemClicked(UnifiedKeyInfo keyInfo) {
|
||||||
ApiApp apiApp = ApiApp.create(packageName, packageSignature);
|
apiAppDao.insertApiApp(packageName, packageSignature);
|
||||||
apiAppDao.insertApiApp(apiApp);
|
|
||||||
apiAppDao.addAllowedKeyIdForApp(packageName, keyInfo.master_key_id());
|
apiAppDao.addAllowedKeyIdForApp(packageName, keyInfo.master_key_id());
|
||||||
resultIntent.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, keyInfo.master_key_id());
|
resultIntent.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, keyInfo.master_key_id());
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.dialog.DialogKeyChoiceAdapter.KeyChoiceViewHolder;
|
import org.sufficientlysecure.keychain.remote.ui.dialog.DialogKeyChoiceAdapter.KeyChoiceViewHolder;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;
|
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ import android.widget.Toast;
|
|||||||
import com.mikepenz.materialdrawer.util.KeyboardUtil;
|
import com.mikepenz.materialdrawer.util.KeyboardUtil;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity;
|
import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicatePresenter.RemoteDeduplicateView;
|
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicatePresenter.RemoteDeduplicateView;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import android.content.Context;
|
|||||||
import androidx.recyclerview.widget.RecyclerView.Adapter;
|
import androidx.recyclerview.widget.RecyclerView.Adapter;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.remote.AutocryptInteractor;
|
import org.sufficientlysecure.keychain.remote.AutocryptInteractor;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicateActivity.DeduplicateViewModel;
|
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteDeduplicateActivity.DeduplicateViewModel;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter;
|
||||||
|
|||||||
@@ -23,9 +23,6 @@ import java.util.List;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import androidx.lifecycle.ViewModel;
|
|
||||||
import androidx.lifecycle.ViewModelProviders;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -33,26 +30,29 @@ import android.content.res.Resources;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.Drawable.ConstantState;
|
import android.graphics.drawable.Drawable.ConstantState;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.fragment.app.DialogFragment;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.core.content.res.ResourcesCompat;
|
|
||||||
import androidx.core.graphics.drawable.DrawableCompat;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import android.view.ContextThemeWrapper;
|
import android.view.ContextThemeWrapper;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.content.res.ResourcesCompat;
|
||||||
|
import androidx.core.graphics.drawable.DrawableCompat;
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.lifecycle.LiveData;
|
||||||
|
import androidx.lifecycle.ViewModel;
|
||||||
|
import androidx.lifecycle.ViewModelProviders;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.mikepenz.materialdrawer.util.KeyboardUtil;
|
import com.mikepenz.materialdrawer.util.KeyboardUtil;
|
||||||
import org.openintents.ssh.authentication.SshAuthenticationApi;
|
import org.openintents.ssh.authentication.SshAuthenticationApi;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity;
|
import org.sufficientlysecure.keychain.remote.ui.RemoteSecurityTokenOperationActivity;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyPresenter.RemoteSelectAuthenticationKeyView;
|
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyPresenter.RemoteSelectAuthenticationKeyView;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
|
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import android.content.pm.PackageManager;
|
|||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyActivity.SelectAuthKeyViewModel;
|
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectAuthenticationKeyActivity.SelectAuthKeyViewModel;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ import org.sufficientlysecure.keychain.R;
|
|||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
||||||
import org.sufficientlysecure.keychain.livedata.PgpKeyGenerationLiveData;
|
import org.sufficientlysecure.keychain.livedata.PgpKeyGenerationLiveData;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectIdentityKeyPresenter.RemoteSelectIdentityKeyView;
|
import org.sufficientlysecure.keychain.remote.ui.dialog.RemoteSelectIdentityKeyPresenter.RemoteSelectIdentityKeyView;
|
||||||
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ import android.text.TextUtils;
|
|||||||
|
|
||||||
import org.openintents.openpgp.util.OpenPgpUtils;
|
import org.openintents.openpgp.util.OpenPgpUtils;
|
||||||
import org.openintents.openpgp.util.OpenPgpUtils.UserId;
|
import org.openintents.openpgp.util.OpenPgpUtils.UserId;
|
||||||
|
import org.sufficientlysecure.keychain.Api_apps;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.model.ApiApp;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||||
@@ -59,7 +59,7 @@ class RemoteSelectIdentityKeyPresenter {
|
|||||||
private Long selectedMasterKeyId;
|
private Long selectedMasterKeyId;
|
||||||
private byte[] generatedKeyData;
|
private byte[] generatedKeyData;
|
||||||
private ApiAppDao apiAppDao;
|
private ApiAppDao apiAppDao;
|
||||||
private ApiApp apiApp;
|
private Api_apps apiApp;
|
||||||
|
|
||||||
|
|
||||||
RemoteSelectIdentityKeyPresenter(Context context, LifecycleOwner lifecycleOwner) {
|
RemoteSelectIdentityKeyPresenter(Context context, LifecycleOwner lifecycleOwner) {
|
||||||
@@ -98,7 +98,7 @@ class RemoteSelectIdentityKeyPresenter {
|
|||||||
Drawable appIcon = packageManager.getApplicationIcon(applicationInfo);
|
Drawable appIcon = packageManager.getApplicationIcon(applicationInfo);
|
||||||
CharSequence appLabel = packageManager.getApplicationLabel(applicationInfo);
|
CharSequence appLabel = packageManager.getApplicationLabel(applicationInfo);
|
||||||
|
|
||||||
apiApp = ApiApp.create(packageName, packageSignature);
|
apiApp = new Api_apps(0L, packageName, packageSignature);
|
||||||
|
|
||||||
view.setTitleClientIconAndName(appIcon, appLabel);
|
view.setTitleClientIconAndName(appIcon, appLabel);
|
||||||
}
|
}
|
||||||
@@ -217,14 +217,14 @@ class RemoteSelectIdentityKeyPresenter {
|
|||||||
|
|
||||||
void onHighlightFinished() {
|
void onHighlightFinished() {
|
||||||
apiAppDao.insertApiApp(apiApp);
|
apiAppDao.insertApiApp(apiApp);
|
||||||
apiAppDao.addAllowedKeyIdForApp(apiApp.package_name(), Objects.requireNonNull(selectedMasterKeyId));
|
apiAppDao.addAllowedKeyIdForApp(apiApp.getPackage_name(), Objects.requireNonNull(selectedMasterKeyId));
|
||||||
view.finishAndReturn(selectedMasterKeyId);
|
view.finishAndReturn(selectedMasterKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onImportOpSuccess(ImportKeyResult result) {
|
void onImportOpSuccess(ImportKeyResult result) {
|
||||||
long importedMasterKeyId = result.getImportedMasterKeyIds()[0];
|
long importedMasterKeyId = result.getImportedMasterKeyIds()[0];
|
||||||
apiAppDao.insertApiApp(apiApp);
|
apiAppDao.insertApiApp(apiApp);
|
||||||
apiAppDao.addAllowedKeyIdForApp(apiApp.package_name(), importedMasterKeyId);
|
apiAppDao.addAllowedKeyIdForApp(apiApp.getPackage_name(), importedMasterKeyId);
|
||||||
view.finishAndReturn(importedMasterKeyId);
|
view.finishAndReturn(importedMasterKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,23 +32,23 @@ import android.net.Uri;
|
|||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.PopupMenu;
|
import android.widget.PopupMenu;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.Keys;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey;
|
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
||||||
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||||
import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
|
import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
|
||||||
import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
|
import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
@@ -131,8 +131,8 @@ public class BackupRestoreFragment extends CryptoOperationFragment<BackupKeyring
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Long getFirstSubKeyWithPassphrase(long masterKeyId) {
|
private Long getFirstSubKeyWithPassphrase(long masterKeyId) {
|
||||||
for (SubKey subKey : keyRepository.getSubKeysByMasterKeyId(masterKeyId)) {
|
for (Keys subKey : keyRepository.getSubKeysByMasterKeyId(masterKeyId)) {
|
||||||
switch (subKey.has_secret()) {
|
switch (subKey.getHas_secret()) {
|
||||||
case PASSPHRASE_EMPTY:
|
case PASSPHRASE_EMPTY:
|
||||||
case DIVERT_TO_CARD:
|
case DIVERT_TO_CARD:
|
||||||
case UNAVAILABLE:
|
case UNAVAILABLE:
|
||||||
@@ -140,7 +140,7 @@ public class BackupRestoreFragment extends CryptoOperationFragment<BackupKeyring
|
|||||||
case GNU_DUMMY:
|
case GNU_DUMMY:
|
||||||
continue;
|
continue;
|
||||||
default: {
|
default: {
|
||||||
return subKey.key_id();
|
return subKey.getKey_id();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
|
import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import android.widget.ImageView;
|
|||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ import java.util.regex.Pattern;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
@@ -38,18 +36,20 @@ import android.widget.Button;
|
|||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
import org.bouncycastle.bcpg.sig.KeyFlags;
|
import org.bouncycastle.bcpg.sig.KeyFlags;
|
||||||
import org.openintents.openpgp.util.OpenPgpUtils;
|
import org.openintents.openpgp.util.OpenPgpUtils;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.Keys;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
|
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
||||||
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
|
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.UploadResult;
|
import org.sufficientlysecure.keychain.operations.results.UploadResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
|
||||||
import org.sufficientlysecure.keychain.service.ChangeUnlockParcel;
|
import org.sufficientlysecure.keychain.service.ChangeUnlockParcel;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
|
||||||
@@ -420,9 +420,9 @@ public class CreateKeyFinalFragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SubKey> subKeys = keyRepository.getSubKeysByMasterKeyId(saveKeyResult.mMasterKeyId);
|
List<Keys> subKeys = keyRepository.getSubKeysByMasterKeyId(saveKeyResult.mMasterKeyId);
|
||||||
for (SubKey subKey : subKeys) {
|
for (Keys subKey : subKeys) {
|
||||||
builder.addOrReplaceSubkeyChange(SubkeyChange.createMoveToSecurityTokenChange(subKey.key_id()));
|
builder.addOrReplaceSubkeyChange(SubkeyChange.createMoveToSecurityTokenChange(subKey.getKey_id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// define new PIN and Admin PIN for the card
|
// define new PIN and Admin PIN for the card
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import org.sufficientlysecure.keychain.R;
|
|||||||
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
|
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
|
||||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||||
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import android.widget.Spinner;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
|
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.RevokeResult;
|
import org.sufficientlysecure.keychain.operations.results.RevokeResult;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput;
|
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput;
|
||||||
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip;
|
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip;
|
||||||
import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
|
import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
|
||||||
@@ -121,8 +121,8 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
|
|||||||
super.onActivityCreated(savedInstanceState);
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
|
||||||
EncryptModeViewModel viewModel = ViewModelProviders.of(this).get(EncryptModeViewModel.class);
|
EncryptModeViewModel viewModel = ViewModelProviders.of(this).get(EncryptModeViewModel.class);
|
||||||
viewModel.getSignKeyLiveData(requireContext()).observe(this, mSignKeySpinner::setData);
|
viewModel.getSignKeyLiveData(requireContext()).observe(getViewLifecycleOwner(), mSignKeySpinner::setData);
|
||||||
viewModel.getEncryptRecipientLiveData(requireContext()).observe(this, mEncryptKeyView::setData);
|
viewModel.getEncryptRecipientLiveData(requireContext()).observe(getViewLifecycleOwner(), mEncryptKeyView::setData);
|
||||||
|
|
||||||
// preselect keys given, from state or arguments
|
// preselect keys given, from state or arguments
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
|||||||
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
|
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.keysync.KeyserverSyncManager;
|
import org.sufficientlysecure.keychain.keysync.KeyserverSyncManager;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.KeySyncParcel;
|
import org.sufficientlysecure.keychain.operations.KeySyncParcel;
|
||||||
import org.sufficientlysecure.keychain.operations.results.BenchmarkResult;
|
import org.sufficientlysecure.keychain.operations.results.BenchmarkResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
@@ -252,7 +252,7 @@ public class KeyListFragment extends RecyclerFragment<FlexibleAdapter<FlexibleKe
|
|||||||
|
|
||||||
GenericViewModel viewModel = ViewModelProviders.of(this).get(GenericViewModel.class);
|
GenericViewModel viewModel = ViewModelProviders.of(this).get(GenericViewModel.class);
|
||||||
LiveData<List<FlexibleKeyItem>> liveData = viewModel.getGenericLiveData(requireContext(), this::loadFlexibleKeyItems);
|
LiveData<List<FlexibleKeyItem>> liveData = viewModel.getGenericLiveData(requireContext(), this::loadFlexibleKeyItems);
|
||||||
liveData.observe(this, this::onLoadKeyItems);
|
liveData.observe(getViewLifecycleOwner(), this::onLoadKeyItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
|
|||||||
@@ -21,23 +21,23 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import android.database.MatrixCursor;
|
import android.database.MatrixCursor;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.lifecycle.LiveData;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
|
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
|
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
||||||
|
import org.sufficientlysecure.keychain.model.UserId;
|
||||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
@@ -85,7 +85,7 @@ public class MultiUserIdsFragment extends Fragment {
|
|||||||
KeyRepository keyRepository = KeyRepository.create(activity);
|
KeyRepository keyRepository = KeyRepository.create(activity);
|
||||||
LiveData<List<UserId>> userIdLiveData =
|
LiveData<List<UserId>> userIdLiveData =
|
||||||
new GenericLiveData<>(getContext(), () -> keyRepository.getUserIds(pubMasterKeyIds));
|
new GenericLiveData<>(getContext(), () -> keyRepository.getUserIds(pubMasterKeyIds));
|
||||||
userIdLiveData.observe(this, this::onUserIdsLoaded);
|
userIdLiveData.observe(getViewLifecycleOwner(), this::onUserIdsLoaded);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ import android.widget.ViewAnimator;
|
|||||||
import org.openintents.openpgp.util.OpenPgpUtils;
|
import org.openintents.openpgp.util.OpenPgpUtils;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import android.widget.ImageView;
|
|||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
|
import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
|||||||
@@ -9,19 +9,19 @@ import java.util.TimeZone;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
import android.text.format.DateFormat;
|
import android.text.format.DateFormat;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible;
|
import eu.davidea.flexibleadapter.items.IFlexible;
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder;
|
import eu.davidea.viewholders.FlexibleViewHolder;
|
||||||
|
import org.sufficientlysecure.keychain.Keys;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Builder;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Builder;
|
||||||
@@ -32,22 +32,22 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
|||||||
|
|
||||||
|
|
||||||
public class SubKeyItem extends AbstractFlexibleItem<SubKeyItem.SubkeyViewHolder> {
|
public class SubKeyItem extends AbstractFlexibleItem<SubKeyItem.SubkeyViewHolder> {
|
||||||
final SubKey subkeyInfo;
|
final Keys subkeyInfo;
|
||||||
private final SubkeyEditViewModel viewModel;
|
private final SubkeyEditViewModel viewModel;
|
||||||
|
|
||||||
SubKeyItem(SubKey subkeyInfo, SubkeyEditViewModel viewModel) {
|
SubKeyItem(Keys subkeyInfo, SubkeyEditViewModel viewModel) {
|
||||||
this.subkeyInfo = subkeyInfo;
|
this.subkeyInfo = subkeyInfo;
|
||||||
this.viewModel = viewModel;
|
this.viewModel = viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
return o instanceof SubKeyItem && ((SubKeyItem) o).subkeyInfo.key_id() == subkeyInfo.key_id();
|
return o instanceof SubKeyItem && ((SubKeyItem) o).subkeyInfo.getKey_id() == subkeyInfo.getKey_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
long key_id = subkeyInfo.key_id();
|
long key_id = subkeyInfo.getKey_id();
|
||||||
return (int) (key_id ^ (key_id >>> 32));
|
return (int) (key_id ^ (key_id >>> 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,13 +100,13 @@ public class SubKeyItem extends AbstractFlexibleItem<SubKeyItem.SubkeyViewHolder
|
|||||||
vActionCancel = itemView.findViewById(R.id.button_subkey_action_cancel);
|
vActionCancel = itemView.findViewById(R.id.button_subkey_action_cancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bind(SubKey subkeyInfo) {
|
void bind(Keys subkeyInfo) {
|
||||||
bindKeyId(subkeyInfo.key_id(), subkeyInfo.rank() == 0);
|
bindKeyId(subkeyInfo.getKey_id(), subkeyInfo.getRank() == 0);
|
||||||
bindKeyDetails(subkeyInfo.algorithm(), subkeyInfo.key_size(), subkeyInfo.key_curve_oid(), subkeyInfo.has_secret());
|
bindKeyDetails(subkeyInfo.getAlgorithm(), subkeyInfo.getKey_size(), subkeyInfo.getKey_curve_oid(), subkeyInfo.getHas_secret());
|
||||||
bindKeyFlags(subkeyInfo.can_certify(), subkeyInfo.can_sign(), subkeyInfo.can_encrypt(), subkeyInfo.can_authenticate());
|
bindKeyFlags(subkeyInfo.getCan_certify(), subkeyInfo.getCan_sign(), subkeyInfo.getCan_encrypt(), subkeyInfo.getCan_authenticate());
|
||||||
|
|
||||||
Date validFrom = new Date(subkeyInfo.validFrom() * 1000);
|
Date validFrom = new Date(subkeyInfo.getValidFrom() * 1000);
|
||||||
Date expiryDate = subkeyInfo.expires() ? new Date(subkeyInfo.expiry() * 1000) : null;
|
Date expiryDate = subkeyInfo.getExpiry() != null ? new Date(subkeyInfo.getExpiry() * 1000) : null;
|
||||||
bindKeyStatus(validFrom, expiryDate, subkeyInfo.is_revoked(), subkeyInfo.is_secure());
|
bindKeyStatus(validFrom, expiryDate, subkeyInfo.is_revoked(), subkeyInfo.is_secure());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,14 +198,14 @@ public class SubKeyItem extends AbstractFlexibleItem<SubKeyItem.SubkeyViewHolder
|
|||||||
vKeyDetails.setText(algorithmStr);
|
vKeyDetails.setText(algorithmStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindSubkeyAction(SubKey subkeyInfo, Builder saveKeyringParcelBuilder) {
|
private void bindSubkeyAction(Keys subkeyInfo, Builder saveKeyringParcelBuilder) {
|
||||||
if (saveKeyringParcelBuilder == null) {
|
if (saveKeyringParcelBuilder == null) {
|
||||||
itemView.setClickable(false);
|
itemView.setClickable(false);
|
||||||
vActionLayout.setVisibility(View.GONE);
|
vActionLayout.setVisibility(View.GONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean isRevokeAction = (saveKeyringParcelBuilder.getMutableRevokeSubKeys().contains(subkeyInfo.key_id()));
|
boolean isRevokeAction = (saveKeyringParcelBuilder.getMutableRevokeSubKeys().contains(subkeyInfo.getKey_id()));
|
||||||
SubkeyChange change = saveKeyringParcelBuilder.getSubkeyChange(subkeyInfo.key_id());
|
SubkeyChange change = saveKeyringParcelBuilder.getSubkeyChange(subkeyInfo.getKey_id());
|
||||||
boolean hasAction = isRevokeAction || change != null;
|
boolean hasAction = isRevokeAction || change != null;
|
||||||
if (!hasAction) {
|
if (!hasAction) {
|
||||||
itemView.setClickable(true);
|
itemView.setClickable(true);
|
||||||
@@ -214,7 +214,7 @@ public class SubKeyItem extends AbstractFlexibleItem<SubKeyItem.SubkeyViewHolder
|
|||||||
}
|
}
|
||||||
|
|
||||||
OnClickListener onClickRemoveModificationListener = v -> {
|
OnClickListener onClickRemoveModificationListener = v -> {
|
||||||
saveKeyringParcelBuilder.removeModificationsForSubkey(subkeyInfo.key_id());
|
saveKeyringParcelBuilder.removeModificationsForSubkey(subkeyInfo.getKey_id());
|
||||||
mAdapter.notifyItemChanged(getAdapterPosition());
|
mAdapter.notifyItemChanged(getAdapterPosition());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -42,16 +42,15 @@ import androidx.lifecycle.ViewModelProviders;
|
|||||||
import androidx.viewpager.widget.ViewPager;
|
import androidx.viewpager.widget.ViewPager;
|
||||||
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
|
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
|
||||||
import com.astuetz.PagerSlidingTabStrip;
|
import com.astuetz.PagerSlidingTabStrip;
|
||||||
|
import org.sufficientlysecure.keychain.Keys;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UserId;
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
|
||||||
|
|
||||||
@@ -112,7 +111,7 @@ public class ViewKeyAdvActivity extends BaseActivity implements OnPageChangeList
|
|||||||
public static class ViewKeyAdvViewModel extends ViewModel {
|
public static class ViewKeyAdvViewModel extends ViewModel {
|
||||||
private Long masterKeyId;
|
private Long masterKeyId;
|
||||||
private LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData;
|
private LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData;
|
||||||
private LiveData<List<SubKey>> subKeyLiveData;
|
private LiveData<List<Keys>> subKeyLiveData;
|
||||||
private LiveData<List<UserId>> userIdsLiveData;
|
private LiveData<List<UserId>> userIdsLiveData;
|
||||||
|
|
||||||
void setMasterKeyId(long masterKeyId) {
|
void setMasterKeyId(long masterKeyId) {
|
||||||
@@ -134,7 +133,7 @@ public class ViewKeyAdvActivity extends BaseActivity implements OnPageChangeList
|
|||||||
return unifiedKeyInfoLiveData;
|
return unifiedKeyInfoLiveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveData<List<SubKey>> getSubkeyLiveData(Context context) {
|
LiveData<List<Keys>> getSubkeyLiveData(Context context) {
|
||||||
if (subKeyLiveData == null) {
|
if (subKeyLiveData == null) {
|
||||||
KeyRepository keyRepository = KeyRepository.create(context);
|
KeyRepository keyRepository = KeyRepository.create(context);
|
||||||
subKeyLiveData = Transformations.switchMap(getUnifiedKeyInfoLiveData(context),
|
subKeyLiveData = Transformations.switchMap(getUnifiedKeyInfoLiveData(context),
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import android.widget.TextView;
|
|||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.ViewKeyAdvActivity.ViewKeyAdvViewModel;
|
import org.sufficientlysecure.keychain.ui.ViewKeyAdvActivity.ViewKeyAdvViewModel;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
|
|||||||
@@ -21,18 +21,11 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel;
|
|
||||||
import androidx.lifecycle.ViewModelProviders;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import android.view.ActionMode;
|
import android.view.ActionMode;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -41,13 +34,20 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ViewAnimator;
|
import android.widget.ViewAnimator;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.lifecycle.ViewModel;
|
||||||
|
import androidx.lifecycle.ViewModelProviders;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter.OnItemClickListener;
|
import eu.davidea.flexibleadapter.FlexibleAdapter.OnItemClickListener;
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible;
|
import eu.davidea.flexibleadapter.items.IFlexible;
|
||||||
|
import org.sufficientlysecure.keychain.Keys;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
@@ -99,8 +99,8 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
|
|||||||
subkeysList.setAdapter(subkeysAdapter);
|
subkeysList.setAdapter(subkeysAdapter);
|
||||||
|
|
||||||
ViewKeyAdvViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyAdvViewModel.class);
|
ViewKeyAdvViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyAdvViewModel.class);
|
||||||
viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(this, this::onLoadUnifiedKeyId);
|
viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(getViewLifecycleOwner(), this::onLoadUnifiedKeyId);
|
||||||
viewModel.getSubkeyLiveData(requireContext()).observe(this, this::onLoadSubKeys);
|
viewModel.getSubkeyLiveData(requireContext()).observe(getViewLifecycleOwner(), this::onLoadSubKeys);
|
||||||
|
|
||||||
subkeyEditViewModel = ViewModelProviders.of(this).get(SubkeyEditViewModel.class);
|
subkeyEditViewModel = ViewModelProviders.of(this).get(SubkeyEditViewModel.class);
|
||||||
}
|
}
|
||||||
@@ -114,9 +114,9 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
|
|||||||
subkeyEditViewModel.unifiedKeyInfo = unifiedKeyInfo;
|
subkeyEditViewModel.unifiedKeyInfo = unifiedKeyInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onLoadSubKeys(List<SubKey> subKeys) {
|
private void onLoadSubKeys(List<Keys> subKeys) {
|
||||||
ArrayList<IFlexible> subKeyItems = new ArrayList<>(subKeys.size());
|
ArrayList<IFlexible> subKeyItems = new ArrayList<>(subKeys.size());
|
||||||
for (SubKey subKey : subKeys) {
|
for (Keys subKey : subKeys) {
|
||||||
subKeyItems.add(new SubKeyItem(subKey, subkeyEditViewModel));
|
subKeyItems.add(new SubKeyItem(subKey, subkeyEditViewModel));
|
||||||
}
|
}
|
||||||
subkeysAdapter.updateDataSet(subKeyItems);
|
subkeysAdapter.updateDataSet(subKeyItems);
|
||||||
@@ -207,7 +207,7 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void editSubkey(int position, SubKeyItem item) {
|
private void editSubkey(int position, SubKeyItem item) {
|
||||||
if (subkeyEditViewModel.skpBuilder.hasModificationsForSubkey(item.subkeyInfo.key_id())) {
|
if (subkeyEditViewModel.skpBuilder.hasModificationsForSubkey(item.subkeyInfo.getKey_id())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,8 +219,8 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
|
|||||||
editSubkeyExpiry(item);
|
editSubkeyExpiry(item);
|
||||||
break;
|
break;
|
||||||
case EditSubkeyDialogFragment.MESSAGE_REVOKE:
|
case EditSubkeyDialogFragment.MESSAGE_REVOKE:
|
||||||
SubKey subKey = item.subkeyInfo;
|
Keys subKey = item.subkeyInfo;
|
||||||
subkeyEditViewModel.skpBuilder.addRevokeSubkey(subKey.key_id());
|
subkeyEditViewModel.skpBuilder.addRevokeSubkey(subKey.getKey_id());
|
||||||
break;
|
break;
|
||||||
case EditSubkeyDialogFragment.MESSAGE_STRIP: {
|
case EditSubkeyDialogFragment.MESSAGE_STRIP: {
|
||||||
editSubkeyToggleStrip(item);
|
editSubkeyToggleStrip(item);
|
||||||
@@ -241,21 +241,21 @@ public class ViewKeyAdvSubkeysFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void editSubkeyToggleStrip(SubKeyItem item) {
|
private void editSubkeyToggleStrip(SubKeyItem item) {
|
||||||
SubKey subKey = item.subkeyInfo;
|
Keys subKey = item.subkeyInfo;
|
||||||
if (subKey.has_secret() == SecretKeyType.GNU_DUMMY) {
|
if (subKey.getHas_secret() == SecretKeyType.GNU_DUMMY) {
|
||||||
// Key is already stripped; this is a no-op.
|
// Key is already stripped; this is a no-op.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
subkeyEditViewModel.skpBuilder.addOrReplaceSubkeyChange(SubkeyChange.createStripChange(subKey.key_id()));
|
subkeyEditViewModel.skpBuilder.addOrReplaceSubkeyChange(SubkeyChange.createStripChange(subKey.getKey_id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void editSubkeyExpiry(SubKeyItem item) {
|
private void editSubkeyExpiry(SubKeyItem item) {
|
||||||
SubKey subKey = item.subkeyInfo;
|
Keys subKey = item.subkeyInfo;
|
||||||
|
|
||||||
final long keyId = subKey.key_id();
|
final long keyId = subKey.getKey_id();
|
||||||
final Long creationDate = subKey.creation();
|
final Long creationDate = subKey.getCreation();
|
||||||
final Long expiryDate = subKey.expiry();
|
final Long expiryDate = subKey.getExpiry();
|
||||||
|
|
||||||
Handler returnHandler = new Handler() {
|
Handler returnHandler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -20,15 +20,11 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModelProviders;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import android.view.ActionMode;
|
import android.view.ActionMode;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -38,10 +34,14 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.ViewAnimator;
|
import android.widget.ViewAnimator;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.lifecycle.ViewModelProviders;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
|
import org.sufficientlysecure.keychain.model.UserId;
|
||||||
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
@@ -196,8 +196,8 @@ public class ViewKeyAdvUserIdsFragment extends Fragment {
|
|||||||
mUserIds.setAdapter(mUserIdsAdapter);
|
mUserIds.setAdapter(mUserIdsAdapter);
|
||||||
|
|
||||||
ViewKeyAdvViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyAdvViewModel.class);
|
ViewKeyAdvViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ViewKeyAdvViewModel.class);
|
||||||
viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(this, this::onLoadUnifiedKeyInfo);
|
viewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(getViewLifecycleOwner(), this::onLoadUnifiedKeyInfo);
|
||||||
viewModel.getUserIdLiveData(requireContext()).observe(this, this::onLoadUserIds);
|
viewModel.getUserIdLiveData(requireContext()).observe(getViewLifecycleOwner(), this::onLoadUserIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onLoadUnifiedKeyInfo(UnifiedKeyInfo unifiedKeyInfo) {
|
public void onLoadUnifiedKeyInfo(UnifiedKeyInfo unifiedKeyInfo) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import eu.davidea.flexibleadapter.items.IFlexible;
|
|||||||
import eu.davidea.viewholders.FlexibleViewHolder;
|
import eu.davidea.viewholders.FlexibleViewHolder;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyDetailsItem.FlexibleKeyItemViewHolder;
|
import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyDetailsItem.FlexibleKeyItemViewHolder;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyItem.FlexibleSectionableKeyItem;
|
import org.sufficientlysecure.keychain.ui.adapter.FlexibleKeyItem.FlexibleSectionableKeyItem;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;
|
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import android.content.res.Resources;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
|
|
||||||
|
|
||||||
public class FlexibleKeyItemFactory {
|
public class FlexibleKeyItemFactory {
|
||||||
|
|||||||
@@ -32,9 +32,6 @@ import android.view.View;
|
|||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.databinding.DataBindingUtil;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.databinding.ImportKeysListItemBinding;
|
import org.sufficientlysecure.keychain.databinding.ImportKeysListItemBinding;
|
||||||
@@ -44,7 +41,7 @@ import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
|||||||
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysListener;
|
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysListener;
|
||||||
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysOperationCallback;
|
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysOperationCallback;
|
||||||
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysResultListener;
|
import org.sufficientlysecure.keychain.keyimport.processing.ImportKeysResultListener;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.ImportOperation;
|
import org.sufficientlysecure.keychain.operations.ImportOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
|
|||||||
import eu.davidea.flexibleadapter.items.IFlexible;
|
import eu.davidea.flexibleadapter.items.IFlexible;
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder;
|
import eu.davidea.viewholders.FlexibleViewHolder;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter.KeyChoiceItem;
|
import org.sufficientlysecure.keychain.ui.adapter.KeyChoiceAdapter.KeyChoiceItem;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;
|
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import android.widget.TextView;
|
|||||||
import android.widget.ViewAnimator;
|
import android.widget.ViewAnimator;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
|
import org.sufficientlysecure.keychain.model.UserId;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.materialchips.ChipView;
|
import org.sufficientlysecure.materialchips.ChipView;
|
||||||
import org.sufficientlysecure.materialchips.ChipsInput;
|
import org.sufficientlysecure.materialchips.ChipsInput;
|
||||||
import org.sufficientlysecure.materialchips.adapter.ChipsAdapter;
|
import org.sufficientlysecure.materialchips.adapter.ChipsAdapter;
|
||||||
@@ -15,7 +16,6 @@ import org.sufficientlysecure.materialchips.util.ViewUtil;
|
|||||||
import org.sufficientlysecure.materialchips.views.DetailedChipView;
|
import org.sufficientlysecure.materialchips.views.DetailedChipView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey;
|
|
||||||
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipAdapter.ItemViewHolder;
|
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipAdapter.ItemViewHolder;
|
||||||
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip;
|
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip;
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ public class EncryptRecipientChipAdapter extends ChipsAdapter<EncryptRecipientCh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SimpleChip simpleChipFromKeyInfo(SubKey.UnifiedKeyInfo keyInfo) {
|
private SimpleChip simpleChipFromKeyInfo(UnifiedKeyInfo keyInfo) {
|
||||||
String name;
|
String name;
|
||||||
String email;
|
String email;
|
||||||
if (keyInfo.name() == null) {
|
if (keyInfo.name() == null) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import android.util.AttributeSet;
|
|||||||
|
|
||||||
import org.sufficientlysecure.materialchips.ChipsInput;
|
import org.sufficientlysecure.materialchips.ChipsInput;
|
||||||
import org.sufficientlysecure.materialchips.adapter.FilterableAdapter.FilterableItem;
|
import org.sufficientlysecure.materialchips.adapter.FilterableAdapter.FilterableItem;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip;
|
import org.sufficientlysecure.keychain.ui.chips.EncryptRecipientChipsInput.EncryptRecipientChip;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ package org.sufficientlysecure.keychain.ui.keyview;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.Transformations;
|
import androidx.lifecycle.Transformations;
|
||||||
import androidx.lifecycle.ViewModel;
|
import androidx.lifecycle.ViewModel;
|
||||||
import android.content.Context;
|
import org.sufficientlysecure.keychain.Key_metadata;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
|
import org.sufficientlysecure.keychain.daos.KeyMetadataDao;
|
||||||
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
||||||
import org.sufficientlysecure.keychain.model.KeyMetadata;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao;
|
||||||
@@ -21,7 +21,7 @@ import org.sufficientlysecure.keychain.ui.keyview.loader.SubkeyStatusDao.KeySubk
|
|||||||
public class KeyFragmentViewModel extends ViewModel {
|
public class KeyFragmentViewModel extends ViewModel {
|
||||||
private LiveData<List<IdentityInfo>> identityInfo;
|
private LiveData<List<IdentityInfo>> identityInfo;
|
||||||
private LiveData<KeySubkeyStatus> subkeyStatus;
|
private LiveData<KeySubkeyStatus> subkeyStatus;
|
||||||
private LiveData<KeyMetadata> keyserverStatus;
|
private LiveData<Key_metadata> keyserverStatus;
|
||||||
|
|
||||||
LiveData<List<IdentityInfo>> getIdentityInfo(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData) {
|
LiveData<List<IdentityInfo>> getIdentityInfo(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData) {
|
||||||
if (identityInfo == null) {
|
if (identityInfo == null) {
|
||||||
@@ -43,7 +43,7 @@ public class KeyFragmentViewModel extends ViewModel {
|
|||||||
return subkeyStatus;
|
return subkeyStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveData<KeyMetadata> getKeyserverStatus(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData) {
|
LiveData<Key_metadata> getKeyserverStatus(Context context, LiveData<UnifiedKeyInfo> unifiedKeyInfoLiveData) {
|
||||||
if (keyserverStatus == null) {
|
if (keyserverStatus == null) {
|
||||||
KeyMetadataDao keyMetadataDao = KeyMetadataDao.create(context);
|
KeyMetadataDao keyMetadataDao = KeyMetadataDao.create(context);
|
||||||
keyserverStatus = Transformations.switchMap(unifiedKeyInfoLiveData,
|
keyserverStatus = Transformations.switchMap(unifiedKeyInfoLiveData,
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
package org.sufficientlysecure.keychain.ui.keyview;
|
package org.sufficientlysecure.keychain.ui.keyview;
|
||||||
|
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import androidx.lifecycle.ViewModel;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import androidx.lifecycle.ViewModel;
|
||||||
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
|
import org.sufficientlysecure.keychain.daos.DatabaseNotifyManager;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
|
import org.sufficientlysecure.keychain.livedata.GenericLiveData;
|
||||||
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
|
|
||||||
|
|
||||||
public class UnifiedKeyInfoViewModel extends ViewModel {
|
public class UnifiedKeyInfoViewModel extends ViewModel {
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ import org.sufficientlysecure.keychain.daos.KeyRepository;
|
|||||||
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
||||||
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
|
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
|
||||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
|
|||||||
@@ -35,11 +35,11 @@ import androidx.fragment.app.DialogFragment;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
import org.sufficientlysecure.keychain.Key_metadata;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||||
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
|
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
|
||||||
import org.sufficientlysecure.keychain.model.KeyMetadata;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
||||||
@@ -265,16 +265,16 @@ public class ViewKeyFragment extends Fragment implements OnMenuItemClickListener
|
|||||||
identitiesAdapter.setData(identityInfos);
|
identitiesAdapter.setData(identityInfos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onLoadKeyMetadata(KeyMetadata keyMetadata) {
|
private void onLoadKeyMetadata(Key_metadata keyMetadata) {
|
||||||
if (keyMetadata == null) {
|
if (keyMetadata == null) {
|
||||||
keyserverStatusView.setDisplayStatusUnknown();
|
keyserverStatusView.setDisplayStatusUnknown();
|
||||||
} else if (keyMetadata.hasBeenUpdated()) {
|
} else if (keyMetadata.getLast_updated() != null) {
|
||||||
if (keyMetadata.isPublished()) {
|
if (keyMetadata.getSeen_on_keyservers() != null && keyMetadata.getSeen_on_keyservers()) {
|
||||||
keyserverStatusView.setDisplayStatusPublished();
|
keyserverStatusView.setDisplayStatusPublished();
|
||||||
} else {
|
} else {
|
||||||
keyserverStatusView.setDisplayStatusNotPublished();
|
keyserverStatusView.setDisplayStatusNotPublished();
|
||||||
}
|
}
|
||||||
keyserverStatusView.setLastUpdated(keyMetadata.last_updated());
|
keyserverStatusView.setLastUpdated(keyMetadata.getLast_updated());
|
||||||
} else {
|
} else {
|
||||||
keyserverStatusView.setDisplayStatusUnknown();
|
keyserverStatusView.setDisplayStatusUnknown();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,47 +22,43 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
import com.squareup.sqldelight.SqlDelightQuery;
|
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
import org.sufficientlysecure.keychain.Autocrypt_peers;
|
||||||
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
|
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer;
|
import org.sufficientlysecure.keychain.daos.UserIdDao;
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket;
|
import org.sufficientlysecure.keychain.model.UserId;
|
||||||
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.PackageIconGetter;
|
import org.sufficientlysecure.keychain.ui.util.PackageIconGetter;
|
||||||
|
|
||||||
|
|
||||||
public class IdentityDao {
|
public class IdentityDao {
|
||||||
private final SupportSQLiteDatabase db;
|
|
||||||
private final PackageIconGetter packageIconGetter;
|
private final PackageIconGetter packageIconGetter;
|
||||||
private final PackageManager packageManager;
|
private final PackageManager packageManager;
|
||||||
private final AutocryptPeerDao autocryptPeerDao;
|
private final AutocryptPeerDao autocryptPeerDao;
|
||||||
|
private final UserIdDao userIdDao;
|
||||||
|
|
||||||
public static IdentityDao getInstance(Context context) {
|
public static IdentityDao getInstance(Context context) {
|
||||||
SupportSQLiteDatabase db = KeychainDatabase.getInstance(context).getWritableDatabase();
|
|
||||||
PackageManager packageManager = context.getPackageManager();
|
PackageManager packageManager = context.getPackageManager();
|
||||||
PackageIconGetter iconGetter = PackageIconGetter.getInstance(context);
|
PackageIconGetter iconGetter = PackageIconGetter.getInstance(context);
|
||||||
AutocryptPeerDao autocryptPeerDao = AutocryptPeerDao.getInstance(context);
|
AutocryptPeerDao autocryptPeerDao = AutocryptPeerDao.getInstance(context);
|
||||||
return new IdentityDao(db, packageManager, iconGetter, autocryptPeerDao);
|
UserIdDao userIdDao = UserIdDao.getInstance(context);
|
||||||
|
return new IdentityDao(packageManager, iconGetter, autocryptPeerDao, userIdDao);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IdentityDao(SupportSQLiteDatabase db,
|
private IdentityDao(PackageManager packageManager,
|
||||||
PackageManager packageManager, PackageIconGetter iconGetter,
|
PackageIconGetter iconGetter, AutocryptPeerDao autocryptPeerDao,
|
||||||
AutocryptPeerDao autocryptPeerDao) {
|
UserIdDao userIdDao) {
|
||||||
this.db = db;
|
|
||||||
this.packageManager = packageManager;
|
this.packageManager = packageManager;
|
||||||
this.packageIconGetter = iconGetter;
|
this.packageIconGetter = iconGetter;
|
||||||
this.autocryptPeerDao = autocryptPeerDao;
|
this.autocryptPeerDao = autocryptPeerDao;
|
||||||
|
this.userIdDao = userIdDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IdentityInfo> getIdentityInfos(long masterKeyId) {
|
public List<IdentityInfo> getIdentityInfos(long masterKeyId) {
|
||||||
@@ -74,29 +70,36 @@ public class IdentityDao {
|
|||||||
return Collections.unmodifiableList(identities);
|
return Collections.unmodifiableList(identities);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void correlateOrAddAutocryptPeers(ArrayList<IdentityInfo> identities, long masterKeyId) {
|
private void correlateOrAddAutocryptPeers(ArrayList<IdentityInfo> identities,
|
||||||
for (AutocryptPeer autocryptPeer : autocryptPeerDao.getAutocryptPeersForKey(masterKeyId)) {
|
long masterKeyId) {
|
||||||
String packageName = autocryptPeer.package_name();
|
for (Autocrypt_peers autocryptPeer : autocryptPeerDao.getAutocryptPeersForKey(
|
||||||
String autocryptId = autocryptPeer.identifier();
|
masterKeyId)) {
|
||||||
|
String packageName = autocryptPeer.getPackage_name();
|
||||||
|
String autocryptId = autocryptPeer.getIdentifier();
|
||||||
|
|
||||||
Drawable drawable = packageIconGetter.getDrawableForPackageName(packageName);
|
Drawable drawable = packageIconGetter.getDrawableForPackageName(packageName);
|
||||||
Intent autocryptPeerIntent = getAutocryptPeerActivityIntentIfResolvable(packageName, autocryptId);
|
Intent autocryptPeerIntent =
|
||||||
|
getAutocryptPeerActivityIntentIfResolvable(packageName, autocryptId);
|
||||||
|
|
||||||
UserIdInfo associatedUserIdInfo = findUserIdMatchingAutocryptPeer(identities, autocryptId);
|
UserIdInfo associatedUserIdInfo =
|
||||||
|
findUserIdMatchingAutocryptPeer(identities, autocryptId);
|
||||||
if (associatedUserIdInfo != null) {
|
if (associatedUserIdInfo != null) {
|
||||||
int position = identities.indexOf(associatedUserIdInfo);
|
int position = identities.indexOf(associatedUserIdInfo);
|
||||||
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
|
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
|
||||||
.create(masterKeyId, associatedUserIdInfo, autocryptId, packageName, drawable, autocryptPeerIntent);
|
.create(masterKeyId, associatedUserIdInfo, autocryptId, packageName,
|
||||||
|
drawable, autocryptPeerIntent);
|
||||||
identities.set(position, autocryptPeerInfo);
|
identities.set(position, autocryptPeerInfo);
|
||||||
} else {
|
} else {
|
||||||
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
|
AutocryptPeerInfo autocryptPeerInfo = AutocryptPeerInfo
|
||||||
.create(masterKeyId, autocryptId, packageName, drawable, autocryptPeerIntent);
|
.create(masterKeyId, autocryptId, packageName, drawable,
|
||||||
|
autocryptPeerIntent);
|
||||||
identities.add(autocryptPeerInfo);
|
identities.add(autocryptPeerInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Intent getAutocryptPeerActivityIntentIfResolvable(String packageName, String autocryptPeer) {
|
private Intent getAutocryptPeerActivityIntentIfResolvable(String packageName,
|
||||||
|
String autocryptPeer) {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.setAction("org.autocrypt.PEER_ACTION");
|
intent.setAction("org.autocrypt.PEER_ACTION");
|
||||||
intent.setPackage(packageName);
|
intent.setPackage(packageName);
|
||||||
@@ -111,7 +114,8 @@ public class IdentityDao {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UserIdInfo findUserIdMatchingAutocryptPeer(List<IdentityInfo> identities, String autocryptPeer) {
|
private static UserIdInfo findUserIdMatchingAutocryptPeer(List<IdentityInfo> identities,
|
||||||
|
String autocryptPeer) {
|
||||||
for (IdentityInfo identityInfo : identities) {
|
for (IdentityInfo identityInfo : identities) {
|
||||||
if (identityInfo instanceof UserIdInfo) {
|
if (identityInfo instanceof UserIdInfo) {
|
||||||
UserIdInfo userIdInfo = (UserIdInfo) identityInfo;
|
UserIdInfo userIdInfo = (UserIdInfo) identityInfo;
|
||||||
@@ -123,72 +127,90 @@ public class IdentityDao {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadUserIds(ArrayList<IdentityInfo> identities, long... masterKeyId) {
|
private void loadUserIds(ArrayList<IdentityInfo> identities, long... masterKeyIds) {
|
||||||
SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyId);
|
for (UserId userId : userIdDao.getUserIdsByMasterKeyIds(masterKeyIds)) {
|
||||||
try (Cursor cursor = db.query(query)) {
|
if (userId.name() != null || userId.email() != null) {
|
||||||
while (cursor.moveToNext()) {
|
IdentityInfo identityInfo = UserIdInfo.create(
|
||||||
UserId userId = UserPacket.USER_ID_MAPPER.map(cursor);
|
userId.master_key_id(), userId.rank(), userId.isVerified(),
|
||||||
|
userId.is_primary(), userId.name(), userId.email(), userId.email());
|
||||||
if (userId.name() != null || userId.email() != null) {
|
identities.add(identityInfo);
|
||||||
IdentityInfo identityInfo = UserIdInfo.create(
|
|
||||||
userId.master_key_id(), userId.rank(), userId.isVerified(), userId.is_primary(), userId.name(), userId.email(), userId.comment());
|
|
||||||
identities.add(identityInfo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IdentityInfo {
|
public interface IdentityInfo {
|
||||||
long getMasterKeyId();
|
long getMasterKeyId();
|
||||||
|
|
||||||
int getRank();
|
int getRank();
|
||||||
|
|
||||||
boolean isVerified();
|
boolean isVerified();
|
||||||
|
|
||||||
boolean isPrimary();
|
boolean isPrimary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public abstract static class UserIdInfo implements IdentityInfo {
|
public abstract static class UserIdInfo implements IdentityInfo {
|
||||||
public abstract long getMasterKeyId();
|
public abstract long getMasterKeyId();
|
||||||
|
|
||||||
public abstract int getRank();
|
public abstract int getRank();
|
||||||
|
|
||||||
public abstract boolean isVerified();
|
public abstract boolean isVerified();
|
||||||
|
|
||||||
public abstract boolean isPrimary();
|
public abstract boolean isPrimary();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract String getName();
|
public abstract String getName();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract String getEmail();
|
public abstract String getEmail();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract String getComment();
|
public abstract String getComment();
|
||||||
|
|
||||||
static UserIdInfo create(long masterKeyId, int rank, boolean isVerified, boolean isPrimary, String name, String email,
|
static UserIdInfo create(long masterKeyId, int rank, boolean isVerified, boolean isPrimary,
|
||||||
|
String name, String email,
|
||||||
String comment) {
|
String comment) {
|
||||||
return new AutoValue_IdentityDao_UserIdInfo(masterKeyId, rank, isVerified, isPrimary, name, email, comment);
|
return new AutoValue_IdentityDao_UserIdInfo(masterKeyId, rank, isVerified, isPrimary,
|
||||||
|
name, email, comment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public abstract static class AutocryptPeerInfo implements IdentityInfo {
|
public abstract static class AutocryptPeerInfo implements IdentityInfo {
|
||||||
public abstract long getMasterKeyId();
|
public abstract long getMasterKeyId();
|
||||||
|
|
||||||
public abstract int getRank();
|
public abstract int getRank();
|
||||||
|
|
||||||
public abstract boolean isVerified();
|
public abstract boolean isVerified();
|
||||||
|
|
||||||
public abstract boolean isPrimary();
|
public abstract boolean isPrimary();
|
||||||
|
|
||||||
public abstract String getIdentity();
|
public abstract String getIdentity();
|
||||||
|
|
||||||
public abstract String getPackageName();
|
public abstract String getPackageName();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract Drawable getAppIcon();
|
public abstract Drawable getAppIcon();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract UserIdInfo getUserIdInfo();
|
public abstract UserIdInfo getUserIdInfo();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract Intent getAutocryptPeerIntent();
|
public abstract Intent getAutocryptPeerIntent();
|
||||||
|
|
||||||
static AutocryptPeerInfo create(long masterKeyId, UserIdInfo userIdInfo, String autocryptPeer, String packageName,
|
static AutocryptPeerInfo create(long masterKeyId, UserIdInfo userIdInfo,
|
||||||
|
String autocryptPeer, String packageName,
|
||||||
Drawable appIcon, Intent autocryptPeerIntent) {
|
Drawable appIcon, Intent autocryptPeerIntent) {
|
||||||
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId, userIdInfo.getRank(), userIdInfo.isVerified(),
|
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId, userIdInfo.getRank(),
|
||||||
userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo, autocryptPeerIntent);
|
userIdInfo.isVerified(),
|
||||||
|
userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo,
|
||||||
|
autocryptPeerIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AutocryptPeerInfo create(long masterKeyId, String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) {
|
static AutocryptPeerInfo create(long masterKeyId, String autocryptPeer, String packageName,
|
||||||
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId,0, false, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent);
|
Drawable appIcon, Intent autocryptPeerIntent) {
|
||||||
|
return new AutoValue_IdentityDao_AutocryptPeerInfo(masterKeyId, 0, false, false,
|
||||||
|
autocryptPeer, packageName, appIcon, null, autocryptPeerIntent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.model.SubKey;
|
import androidx.annotation.NonNull;
|
||||||
|
import org.sufficientlysecure.keychain.Keys;
|
||||||
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants;
|
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants;
|
||||||
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
|
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
|
||||||
|
|
||||||
|
|
||||||
public class SubkeyStatusDao {
|
public class SubkeyStatusDao {
|
||||||
@@ -51,7 +51,7 @@ public class SubkeyStatusDao {
|
|||||||
SubKeyItem keyCertify = null;
|
SubKeyItem keyCertify = null;
|
||||||
ArrayList<SubKeyItem> keysSign = new ArrayList<>();
|
ArrayList<SubKeyItem> keysSign = new ArrayList<>();
|
||||||
ArrayList<SubKeyItem> keysEncrypt = new ArrayList<>();
|
ArrayList<SubKeyItem> keysEncrypt = new ArrayList<>();
|
||||||
for (SubKey subKey : keyRepository.getSubKeysByMasterKeyId(masterKeyId)) {
|
for (Keys subKey : keyRepository.getSubKeysByMasterKeyId(masterKeyId)) {
|
||||||
SubKeyItem ski = new SubKeyItem(masterKeyId, subKey);
|
SubKeyItem ski = new SubKeyItem(masterKeyId, subKey);
|
||||||
|
|
||||||
if (ski.mKeyId == masterKeyId) {
|
if (ski.mKeyId == masterKeyId) {
|
||||||
@@ -183,23 +183,23 @@ public class SubkeyStatusDao {
|
|||||||
final boolean mCanCertify, mCanSign, mCanEncrypt;
|
final boolean mCanCertify, mCanSign, mCanEncrypt;
|
||||||
public final KeySecurityProblem mSecurityProblem;
|
public final KeySecurityProblem mSecurityProblem;
|
||||||
|
|
||||||
SubKeyItem(long masterKeyId, SubKey subKey) {
|
SubKeyItem(long masterKeyId, Keys subKey) {
|
||||||
mKeyId = subKey.key_id();
|
mKeyId = subKey.getKey_id();
|
||||||
mCreation = new Date(subKey.creation() * 1000);
|
mCreation = new Date(subKey.getCreation() * 1000);
|
||||||
|
|
||||||
mSecretKeyType = subKey.has_secret();
|
mSecretKeyType = subKey.getHas_secret();
|
||||||
|
|
||||||
mIsRevoked = subKey.is_revoked();
|
mIsRevoked = subKey.is_revoked();
|
||||||
mExpiry = subKey.expiry() == null ? null : new Date(subKey.expiry() * 1000);
|
mExpiry = subKey.getExpiry() == null ? null : new Date(subKey.getExpiry() * 1000);
|
||||||
mIsExpired = mExpiry != null && mExpiry.before(new Date());
|
mIsExpired = mExpiry != null && mExpiry.before(new Date());
|
||||||
|
|
||||||
mCanCertify = subKey.can_certify();
|
mCanCertify = subKey.getCan_certify();
|
||||||
mCanSign = subKey.can_sign();
|
mCanSign = subKey.getCan_sign();
|
||||||
mCanEncrypt = subKey.can_encrypt();
|
mCanEncrypt = subKey.getCan_encrypt();
|
||||||
|
|
||||||
int algorithm = subKey.algorithm();
|
int algorithm = subKey.getAlgorithm();
|
||||||
Integer bitStrength = subKey.key_size();
|
Integer bitStrength = subKey.getKey_size();
|
||||||
String curveOid = subKey.key_curve_oid();
|
String curveOid = subKey.getKey_curve_oid();
|
||||||
|
|
||||||
mSecurityProblem = PgpSecurityConstants.getKeySecurityProblem(
|
mSecurityProblem = PgpSecurityConstants.getKeySecurityProblem(
|
||||||
masterKeyId, mKeyId, algorithm, bitStrength, curveOid);
|
masterKeyId, mKeyId, algorithm, bitStrength, curveOid);
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -150,7 +149,7 @@ public class KeyInfoFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private String getSecretKeyReadableTime(Context context, SubKey.UnifiedKeyInfo keyInfo) {
|
private String getSecretKeyReadableTime(Context context, UnifiedKeyInfo keyInfo) {
|
||||||
long creationMillis = keyInfo.creation() * 1000;
|
long creationMillis = keyInfo.creation() * 1000;
|
||||||
|
|
||||||
boolean allowRelativeTimestamp = keyInfo.has_duplicate();
|
boolean allowRelativeTimestamp = keyInfo.has_duplicate();
|
||||||
|
|||||||
@@ -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.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,7 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;
|
import org.sufficientlysecure.keychain.ui.util.KeyInfoFormatter;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import android.view.View;
|
|||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
|
|
||||||
public class KeySpinner extends AppCompatSpinner {
|
public class KeySpinner extends AppCompatSpinner {
|
||||||
public static final String ARG_SUPER_STATE = "super_state";
|
public static final String ARG_SUPER_STATE = "super_state";
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
import org.sufficientlysecure.keychain.daos.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
import org.sufficientlysecure.keychain.daos.KeyRepository.NotFoundException;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
|
||||||
import org.sufficientlysecure.keychain.pgp.SshPublicKey;
|
import org.sufficientlysecure.keychain.pgp.SshPublicKey;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
|
|||||||
@@ -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>
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
CREATE TABLE IF NOT EXISTS api_allowed_keys (
|
CREATE TABLE IF NOT EXISTS api_allowed_keys (
|
||||||
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
key_id INTEGER,
|
key_id INTEGER NOT NULL,
|
||||||
package_name TEXT NOT NULL,
|
package_name TEXT NOT NULL,
|
||||||
UNIQUE (key_id, package_name),
|
UNIQUE (key_id, package_name),
|
||||||
FOREIGN KEY (package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE
|
FOREIGN KEY (package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
|
import org.sufficientlysecure.keychain.model.GossipOrigin;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS autocrypt_peers (
|
CREATE TABLE IF NOT EXISTS autocrypt_peers (
|
||||||
package_name TEXT NOT NULL,
|
package_name TEXT NOT NULL,
|
||||||
identifier TEXT NOT NULL,
|
identifier TEXT NOT NULL,
|
||||||
last_seen INTEGER AS Date NULL,
|
last_seen INTEGER AS Date,
|
||||||
last_seen_key INTEGER AS Date NULL,
|
last_seen_key INTEGER AS Date,
|
||||||
is_mutual INTEGER AS Boolean NOT NULL DEFAULT 0,
|
is_mutual INTEGER AS Boolean NOT NULL DEFAULT 0,
|
||||||
master_key_id INTEGER NULL,
|
master_key_id INTEGER,
|
||||||
gossip_master_key_id INTEGER NULL,
|
gossip_master_key_id INTEGER,
|
||||||
gossip_last_seen_key INTEGER AS Date NULL,
|
gossip_last_seen_key INTEGER AS Date,
|
||||||
gossip_origin INTEGER AS GossipOrigin NULL,
|
gossip_origin INTEGER AS GossipOrigin,
|
||||||
PRIMARY KEY(package_name, identifier),
|
PRIMARY KEY(package_name, identifier),
|
||||||
FOREIGN KEY(package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE
|
FOREIGN KEY(package_name) REFERENCES api_apps (package_name) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
@@ -54,10 +54,10 @@ selectAutocryptKeyStatus:
|
|||||||
SELECT autocryptPeer.*,
|
SELECT autocryptPeer.*,
|
||||||
(CASE WHEN ac_key.expiry IS NULL THEN 0 WHEN ac_key.expiry > strftime('%s', 'now') THEN 0 ELSE 1 END) AS key_is_expired_int,
|
(CASE WHEN ac_key.expiry IS NULL THEN 0 WHEN ac_key.expiry > strftime('%s', 'now') THEN 0 ELSE 1 END) AS key_is_expired_int,
|
||||||
(CASE WHEN gossip_key.expiry IS NULL THEN 0 WHEN gossip_key.expiry > strftime('%s', 'now') THEN 0 ELSE 1 END) AS gossip_key_is_expired_int,
|
(CASE WHEN gossip_key.expiry IS NULL THEN 0 WHEN gossip_key.expiry > strftime('%s', 'now') THEN 0 ELSE 1 END) AS gossip_key_is_expired_int,
|
||||||
ac_key.is_revoked AS key_is_revoked_int,
|
ac_key.is_revoked AS key_is_revoked,
|
||||||
gossip_key.is_revoked AS gossip_key_is_revoked_int,
|
gossip_key.is_revoked AS gossip_key_is_revoked,
|
||||||
EXISTS (SELECT * FROM certs WHERE certs.master_key_id = autocryptPeer.master_key_id AND verified = 1 ) AS key_is_verified_int,
|
EXISTS (SELECT * FROM certs WHERE certs.master_key_id = autocryptPeer.master_key_id AND verified = 1) AS key_is_verified,
|
||||||
EXISTS (SELECT * FROM certs WHERE certs.master_key_id = autocryptPeer.gossip_master_key_id AND verified = 1 ) AS gossip_key_is_verified_int
|
EXISTS (SELECT * FROM certs WHERE certs.master_key_id = autocryptPeer.gossip_master_key_id AND verified = 1) AS gossip_key_is_verified
|
||||||
FROM autocrypt_peers AS autocryptPeer
|
FROM autocrypt_peers AS autocryptPeer
|
||||||
LEFT JOIN keys AS ac_key ON (ac_key.master_key_id = autocryptPeer.master_key_id AND ac_key.rank = 0)
|
LEFT JOIN keys AS ac_key ON (ac_key.master_key_id = autocryptPeer.master_key_id AND ac_key.rank = 0)
|
||||||
LEFT JOIN keys AS gossip_key ON (gossip_key.master_key_id = gossip_master_key_id AND gossip_key.rank = 0)
|
LEFT JOIN keys AS gossip_key ON (gossip_key.master_key_id = gossip_master_key_id AND gossip_key.rank = 0)
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ CREATE TABLE IF NOT EXISTS certs(
|
|||||||
);
|
);
|
||||||
|
|
||||||
insertCert:
|
insertCert:
|
||||||
INSERT INTO certs (master_key_id, rank, key_id_certifier, type, verified, creation, data) VALUES (?, ?, ?, ?, ?, ?, ?);
|
INSERT INTO certs VALUES ?;
|
||||||
|
|
||||||
selectVerifyingCertDetails:
|
selectVerifyingCertDetails:
|
||||||
SELECT master_key_id AS masterKeyId, key_id_certifier AS signerMasterKeyId, creation * 1000 AS creation
|
SELECT master_key_id AS masterKeyId, key_id_certifier AS signerMasterKeyId, creation * 1000 AS creation
|
||||||
FROM certs
|
FROM certs
|
||||||
WHERE verified = 1 AND master_key_id = ? AND rank = ?
|
WHERE verified = 1 AND master_key_id = ? AND rank = ?
|
||||||
ORDER BY creation DESC
|
ORDER BY certs.creation DESC
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
@@ -16,7 +16,7 @@ SELECT *
|
|||||||
|
|
||||||
deleteAllLastUpdatedTimes:
|
deleteAllLastUpdatedTimes:
|
||||||
UPDATE key_metadata
|
UPDATE key_metadata
|
||||||
SET last_updated = null, seen_on_keyservers = null;
|
SET last_updated = NULL, seen_on_keyservers = NULL;
|
||||||
|
|
||||||
replaceKeyMetadata:
|
replaceKeyMetadata:
|
||||||
REPLACE INTO key_metadata (master_key_id, last_updated, seen_on_keyservers) VALUES (?, ?, ?);
|
REPLACE INTO key_metadata (master_key_id, last_updated, seen_on_keyservers) VALUES (?, ?, ?);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
CREATE TABLE IF NOT EXISTS keyrings_public (
|
CREATE TABLE IF NOT EXISTS keyrings_public (
|
||||||
master_key_id INTEGER NOT NULL PRIMARY KEY,
|
master_key_id INTEGER NOT NULL PRIMARY KEY,
|
||||||
key_ring_data BLOB NULL
|
key_ring_data BLOB
|
||||||
);
|
);
|
||||||
|
|
||||||
insertKeyRingPublic:
|
insertKeyRingPublic:
|
||||||
INSERT INTO keyrings_public (master_key_id, key_ring_data) VALUES (?, ?);
|
INSERT INTO keyrings_public (master_key_id, key_ring_data) VALUES ?;
|
||||||
|
|
||||||
selectAllMasterKeyIds:
|
selectAllMasterKeyIds:
|
||||||
SELECT master_key_id
|
SELECT master_key_id
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ CREATE TABLE IF NOT EXISTS key_signatures (
|
|||||||
);
|
);
|
||||||
|
|
||||||
insertKeySignature:
|
insertKeySignature:
|
||||||
INSERT INTO key_signatures (master_key_id, signer_key_id) VALUES (?, ?);
|
INSERT INTO key_signatures (master_key_id, signer_key_id) VALUES ?;
|
||||||
|
|
||||||
selectMasterKeyIdsBySigner:
|
selectMasterKeyIdsBySigner:
|
||||||
SELECT master_key_id
|
SELECT master_key_id
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ INSERT INTO keys (
|
|||||||
master_key_id, rank, key_id, key_size, key_curve_oid, algorithm, fingerprint,
|
master_key_id, rank, key_id, key_size, key_curve_oid, algorithm, fingerprint,
|
||||||
can_certify, can_sign, can_encrypt, can_authenticate,
|
can_certify, can_sign, can_encrypt, can_authenticate,
|
||||||
is_revoked, has_secret, is_secure, creation, expiry, validFrom
|
is_revoked, has_secret, is_secure, creation, expiry, validFrom
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
) VALUES ?;
|
||||||
|
|
||||||
updateHasSecretByMasterKeyId:
|
updateHasSecretByMasterKeyId:
|
||||||
UPDATE keys
|
UPDATE keys
|
||||||
@@ -56,11 +56,11 @@ SELECT master_key_id, rank, key_id, key_size, key_curve_oid, algorithm, fingerpr
|
|||||||
unifiedKeyView:
|
unifiedKeyView:
|
||||||
CREATE VIEW unifiedKeyView AS
|
CREATE VIEW unifiedKeyView AS
|
||||||
SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.user_id, user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, keys.can_certify, certs.verified,
|
SELECT keys.master_key_id, keys.fingerprint, MIN(user_packets.rank), user_packets.user_id, user_packets.name, user_packets.email, user_packets.comment, keys.creation, keys.expiry, keys.is_revoked, keys.is_secure, keys.can_certify, certs.verified,
|
||||||
(EXISTS (SELECT * FROM user_packets AS dups WHERE dups.master_key_id != keys.master_key_id AND dups.rank = 0 AND dups.name = user_packets.name COLLATE NOCASE AND dups.email = user_packets.email COLLATE NOCASE )) AS has_duplicate_int,
|
(EXISTS (SELECT * FROM user_packets AS dups WHERE dups.master_key_id != keys.master_key_id AND dups.rank = 0 AND dups.name = user_packets.name COLLATE NOCASE AND dups.email = user_packets.email COLLATE NOCASE )) AS has_duplicate,
|
||||||
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.has_secret != 0 )) AS has_any_secret_int,
|
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.has_secret != 0)) AS has_any_secret,
|
||||||
(SELECT key_id FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_encrypt != 0 LIMIT 1) AS has_encrypt_key_int,
|
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_encrypt != 0)) AS has_encrypt_key,
|
||||||
(SELECT key_id FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_sign != 0 LIMIT 1) AS has_sign_key_int,
|
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_sign != 0)) AS has_sign_key,
|
||||||
(SELECT key_id FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_authenticate != 0 LIMIT 1) AS has_auth_key_int,
|
(EXISTS (SELECT * FROM keys AS k WHERE k.master_key_id = keys.master_key_id AND k.can_authenticate != 0)) AS has_auth_key,
|
||||||
GROUP_CONCAT(DISTINCT aTI.package_name) AS autocrypt_package_names_csv,
|
GROUP_CONCAT(DISTINCT aTI.package_name) AS autocrypt_package_names_csv,
|
||||||
GROUP_CONCAT(user_packets.user_id, '|||') AS user_id_list
|
GROUP_CONCAT(user_packets.user_id, '|||') AS user_id_list
|
||||||
FROM keys
|
FROM keys
|
||||||
@@ -72,7 +72,7 @@ CREATE VIEW unifiedKeyView AS
|
|||||||
|
|
||||||
selectAllUnifiedKeyInfo:
|
selectAllUnifiedKeyInfo:
|
||||||
SELECT * FROM unifiedKeyView
|
SELECT * FROM unifiedKeyView
|
||||||
ORDER BY has_any_secret_int DESC, IFNULL(name, email) COLLATE NOCASE ASC, creation DESC;
|
ORDER BY has_any_secret DESC, IFNULL(name, email) COLLATE NOCASE ASC, creation DESC;
|
||||||
|
|
||||||
selectUnifiedKeyInfoByMasterKeyId:
|
selectUnifiedKeyInfoByMasterKeyId:
|
||||||
SELECT * FROM unifiedKeyView
|
SELECT * FROM unifiedKeyView
|
||||||
@@ -89,12 +89,12 @@ SELECT * FROM unifiedKeyView
|
|||||||
|
|
||||||
selectAllUnifiedKeyInfoWithSecret:
|
selectAllUnifiedKeyInfoWithSecret:
|
||||||
SELECT * FROM unifiedKeyView
|
SELECT * FROM unifiedKeyView
|
||||||
WHERE has_any_secret_int = 1
|
WHERE has_any_secret = 1
|
||||||
ORDER BY creation DESC;
|
ORDER BY creation DESC;
|
||||||
|
|
||||||
selectAllUnifiedKeyInfoWithAuthKeySecret:
|
selectAllUnifiedKeyInfoWithAuthKeySecret:
|
||||||
SELECT * FROM unifiedKeyView
|
SELECT * FROM unifiedKeyView
|
||||||
WHERE has_any_secret_int = 1 AND has_auth_key_int IS NOT NULL
|
WHERE has_any_secret = 1 AND has_auth_key IS NOT NULL
|
||||||
ORDER BY creation DESC;
|
ORDER BY creation DESC;
|
||||||
|
|
||||||
selectMasterKeyIdBySubkey:
|
selectMasterKeyIdBySubkey:
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ CREATE TABLE IF NOT EXISTS user_packets(
|
|||||||
);
|
);
|
||||||
|
|
||||||
insertUserPacket:
|
insertUserPacket:
|
||||||
INSERT INTO user_packets (master_key_id, rank, type, user_id, name, email, comment, attribute_data, is_primary, is_revoked)
|
INSERT INTO user_packets VALUES ?;
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
|
||||||
|
|
||||||
selectUserIdsByMasterKeyId:
|
selectUserIdsByMasterKeyId:
|
||||||
SELECT user_packets.master_key_id, user_packets.rank, user_id, name, email, comment, is_primary, is_revoked, MIN(certs.verified) AS verified_int
|
SELECT user_packets.master_key_id, user_packets.rank, user_id, name, email, comment, is_primary, is_revoked, MIN(certs.verified) AS verified_int
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
selectChanges:
|
||||||
|
SELECT changes();
|
||||||
@@ -34,7 +34,7 @@ import org.junit.runner.RunWith;
|
|||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.shadows.ShadowLog;
|
import org.robolectric.shadows.ShadowLog;
|
||||||
import org.sufficientlysecure.keychain.KeychainTestRunner;
|
import org.sufficientlysecure.keychain.KeychainTestRunner;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import org.apache.tools.ant.util.StringUtils;
|
|
||||||
import org.bouncycastle.bcpg.BCPGInputStream;
|
import org.bouncycastle.bcpg.BCPGInputStream;
|
||||||
import org.bouncycastle.bcpg.Packet;
|
import org.bouncycastle.bcpg.Packet;
|
||||||
import org.bouncycastle.bcpg.PacketTags;
|
import org.bouncycastle.bcpg.PacketTags;
|
||||||
@@ -388,9 +387,9 @@ public class PgpEncryptDecryptTest {
|
|||||||
|
|
||||||
Assert.assertTrue("verification must succeed", result.success());
|
Assert.assertTrue("verification must succeed", result.success());
|
||||||
|
|
||||||
Assert.assertTrue("verification text should equal plaintext (ignoring newlines)",
|
Assert.assertEquals("verification text should equal plaintext (ignoring newlines)",
|
||||||
new String(out.toByteArray()).replace(StringUtils.LINE_SEP, "")
|
out.toString().replace("\r", "").replace("\n", ""),
|
||||||
.equals(plaintext.replace("\r", "").replace("\n", "")));
|
plaintext.replace("\r", "").replace("\n", ""));
|
||||||
Assert.assertEquals("decryptionResult should be RESULT_NOT_ENCRYPTED",
|
Assert.assertEquals("decryptionResult should be RESULT_NOT_ENCRYPTED",
|
||||||
OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED, result.getDecryptionResult().getResult());
|
OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED, result.getDecryptionResult().getResult());
|
||||||
Assert.assertEquals("signatureResult should be RESULT_VALID_CONFIRMED",
|
Assert.assertEquals("signatureResult should be RESULT_VALID_CONFIRMED",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import org.robolectric.RuntimeEnvironment;
|
|||||||
import org.robolectric.shadows.ShadowLog;
|
import org.robolectric.shadows.ShadowLog;
|
||||||
import org.sufficientlysecure.keychain.KeychainTestRunner;
|
import org.sufficientlysecure.keychain.KeychainTestRunner;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
||||||
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
|
import org.sufficientlysecure.keychain.model.UnifiedKeyInfo;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||||
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||||
@@ -128,7 +128,6 @@ public class KeyRepositorySaveTest {
|
|||||||
CanonicalizedPublicKeyRing pubRing = mDatabaseInteractor.getCanonicalizedPublicKeyRing(keyId);
|
CanonicalizedPublicKeyRing pubRing = mDatabaseInteractor.getCanonicalizedPublicKeyRing(keyId);
|
||||||
|
|
||||||
Assert.assertEquals("master key should be encryption key", keyId, pubRing.getEncryptId());
|
Assert.assertEquals("master key should be encryption key", keyId, pubRing.getEncryptId());
|
||||||
Assert.assertEquals("master key should be encryption key (cached)", keyId, unifiedKeyInfo.has_encrypt_key_int());
|
|
||||||
|
|
||||||
Assert.assertEquals("canonicalized key flags should be zero",
|
Assert.assertEquals("canonicalized key flags should be zero",
|
||||||
0, (long) pubRing.getPublicKey().getKeyUsage());
|
0, (long) pubRing.getPublicKey().getKeyUsage());
|
||||||
|
|||||||
@@ -17,15 +17,13 @@ import org.junit.runner.RunWith;
|
|||||||
import org.robolectric.Robolectric;
|
import org.robolectric.Robolectric;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.shadows.ShadowBinder;
|
import org.robolectric.shadows.ShadowBinder;
|
||||||
import org.robolectric.shadows.ShadowContentResolver;
|
|
||||||
import org.robolectric.shadows.ShadowLog;
|
import org.robolectric.shadows.ShadowLog;
|
||||||
import org.robolectric.shadows.ShadowPackageManager;
|
import org.robolectric.shadows.ShadowPackageManager;
|
||||||
import org.sufficientlysecure.keychain.KeychainTestRunner;
|
import org.sufficientlysecure.keychain.KeychainTestRunner;
|
||||||
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
import org.sufficientlysecure.keychain.daos.ApiAppDao;
|
||||||
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
|
import org.sufficientlysecure.keychain.daos.AutocryptPeerDao;
|
||||||
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
||||||
import org.sufficientlysecure.keychain.model.ApiApp;
|
import org.sufficientlysecure.keychain.model.GossipOrigin;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer.GossipOrigin;
|
|
||||||
import org.sufficientlysecure.keychain.operations.CertifyOperation;
|
import org.sufficientlysecure.keychain.operations.CertifyOperation;
|
||||||
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
|
||||||
@@ -59,8 +57,8 @@ public class KeychainExternalProviderTest {
|
|||||||
|
|
||||||
|
|
||||||
KeyWritableRepository databaseInteractor =
|
KeyWritableRepository databaseInteractor =
|
||||||
KeyWritableRepository.create(RuntimeEnvironment.application);
|
KeyWritableRepository.create(RuntimeEnvironment.getApplication());
|
||||||
ContentResolver contentResolver = RuntimeEnvironment.application.getContentResolver();
|
ContentResolver contentResolver = RuntimeEnvironment.getApplication().getContentResolver();
|
||||||
ApiPermissionHelper apiPermissionHelper;
|
ApiPermissionHelper apiPermissionHelper;
|
||||||
ApiAppDao apiAppDao;
|
ApiAppDao apiAppDao;
|
||||||
AutocryptPeerDao autocryptPeerDao;
|
AutocryptPeerDao autocryptPeerDao;
|
||||||
@@ -87,7 +85,7 @@ public class KeychainExternalProviderTest {
|
|||||||
apiPermissionHelper = new ApiPermissionHelper(RuntimeEnvironment.application, apiAppDao);
|
apiPermissionHelper = new ApiPermissionHelper(RuntimeEnvironment.application, apiAppDao);
|
||||||
autocryptPeerDao = AutocryptPeerDao.getInstance(RuntimeEnvironment.application);
|
autocryptPeerDao = AutocryptPeerDao.getInstance(RuntimeEnvironment.application);
|
||||||
|
|
||||||
apiAppDao.insertApiApp(ApiApp.create(PACKAGE_NAME, PACKAGE_SIGNATURE));
|
apiAppDao.insertApiApp(PACKAGE_NAME, PACKAGE_SIGNATURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = AccessControlException.class)
|
@Test(expected = AccessControlException.class)
|
||||||
@@ -104,7 +102,7 @@ public class KeychainExternalProviderTest {
|
|||||||
@Test(expected = AccessControlException.class)
|
@Test(expected = AccessControlException.class)
|
||||||
public void testPermission__withWrongPackageCert() throws Exception {
|
public void testPermission__withWrongPackageCert() throws Exception {
|
||||||
apiAppDao.deleteApiApp(PACKAGE_NAME);
|
apiAppDao.deleteApiApp(PACKAGE_NAME);
|
||||||
apiAppDao.insertApiApp(ApiApp.create(PACKAGE_NAME, new byte[] { 1, 2, 4 }));
|
apiAppDao.insertApiApp(PACKAGE_NAME, new byte[] { 1, 2, 4 });
|
||||||
|
|
||||||
contentResolver.query(
|
contentResolver.query(
|
||||||
AutocryptStatus.CONTENT_URI,
|
AutocryptStatus.CONTENT_URI,
|
||||||
|
|||||||
10
build.gradle
10
build.gradle
@@ -1,4 +1,8 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
|
ext {
|
||||||
|
kotlin_version = '1.8.20'
|
||||||
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -6,8 +10,10 @@ buildscript {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// NOTE: Always use fixed version codes not dynamic ones, e.g. 0.7.3 instead of 0.7.+, see README for more information
|
// NOTE: Always use fixed version codes not dynamic ones, e.g. 0.7.3 instead of 0.7.+, see README for more information
|
||||||
classpath 'com.android.tools.build:gradle:4.2.2'
|
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||||
classpath 'com.squareup.sqldelight:gradle-plugin:0.8.0'
|
// classpath 'com.squareup.sqldelight:gradle-plugin:0.8.0'
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
classpath 'com.squareup.sqldelight:gradle-plugin:1.5.4'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
extern/bouncycastle
vendored
2
extern/bouncycastle
vendored
Submodule extern/bouncycastle updated: d920f59594...187ca21dd4
2
extern/openpgp-api-lib
vendored
2
extern/openpgp-api-lib
vendored
Submodule extern/openpgp-api-lib updated: 8bc98b412b...f91db6be30
@@ -1,4 +1,4 @@
|
|||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.jetifier.blacklist=bcprov-jdk15on
|
android.jetifier.ignorelist=bcprov-jdk15on
|
||||||
org.gradle.jvmargs=-Xms128m -Xmx4096m -XX:+CMSClassUnloadingEnabled
|
org.gradle.jvmargs=-Xms128m -Xmx4096m -XX:+CMSClassUnloadingEnabled
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user