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