From 6585e7113d2424e9df45b3ec71c7005b182cbd97 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 19 Jun 2018 15:11:04 +0200 Subject: [PATCH] move loading of certs into CertificationDao --- .../keychain/livedata/CertificationDao.java | 41 ++++++++++ .../keychain/livedata/GenericLiveData.java | 26 +++++++ .../keychain/model/Certification.java | 20 +++++ .../keychain/provider/KeychainContract.java | 7 -- .../keychain/provider/KeychainProvider.java | 54 ------------- .../ui/keyview/LinkedIdViewFragment.java | 19 +++-- .../keychain/ui/widget/CertListWidget.java | 76 ++----------------- .../org/sufficientlysecure/keychain/Certs.sq | 23 ++++-- 8 files changed, 120 insertions(+), 146 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/CertificationDao.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/GenericLiveData.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/Certification.java diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/CertificationDao.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/CertificationDao.java new file mode 100644 index 000000000..e6236bd41 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/CertificationDao.java @@ -0,0 +1,41 @@ +package org.sufficientlysecure.keychain.livedata; + + +import android.arch.persistence.db.SupportSQLiteDatabase; +import android.content.Context; +import android.database.Cursor; + +import com.squareup.sqldelight.SqlDelightQuery; +import org.sufficientlysecure.keychain.model.Certification; +import org.sufficientlysecure.keychain.model.Certification.CertDetails; +import org.sufficientlysecure.keychain.provider.DatabaseNotifyManager; +import org.sufficientlysecure.keychain.provider.KeychainDatabase; + + +public class CertificationDao { + private final SupportSQLiteDatabase db; + private final DatabaseNotifyManager databaseNotifyManager; + + public static CertificationDao getInstance(Context context) { + KeychainDatabase keychainDatabase = new KeychainDatabase(context); + DatabaseNotifyManager databaseNotifyManager = DatabaseNotifyManager.create(context); + + return new CertificationDao(keychainDatabase.getWritableDatabase(), databaseNotifyManager); + } + + private CertificationDao(SupportSQLiteDatabase writableDatabase, DatabaseNotifyManager databaseNotifyManager) { + this.db = writableDatabase; + this.databaseNotifyManager = databaseNotifyManager; + } + + public CertDetails getVerifyingCertDetails(long masterKeyId, int userPacketRank) { + SqlDelightQuery query = Certification.FACTORY.selectVerifyingCertDetails(masterKeyId, userPacketRank); + try (Cursor cursor = db.query(query)) { + if (cursor.moveToFirst()) { + return Certification.CERT_DETAILS_MAPPER.map(cursor); + } + } + return null; + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/GenericLiveData.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/GenericLiveData.java new file mode 100644 index 000000000..f46c731db --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/livedata/GenericLiveData.java @@ -0,0 +1,26 @@ +package org.sufficientlysecure.keychain.livedata; + + +import android.content.Context; +import android.net.Uri; + +import org.sufficientlysecure.keychain.ui.keyview.loader.AsyncTaskLiveData; + + +public class GenericLiveData extends AsyncTaskLiveData { + private GenericDataLoader genericDataLoader; + + public GenericLiveData(Context context, Uri uri, GenericDataLoader genericDataLoader) { + super(context, uri); + this.genericDataLoader = genericDataLoader; + } + + @Override + protected T asyncLoadData() { + return genericDataLoader.loadData(); + } + + public interface GenericDataLoader { + T loadData(); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/Certification.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/Certification.java new file mode 100644 index 000000000..b9c72596e --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/Certification.java @@ -0,0 +1,20 @@ +package org.sufficientlysecure.keychain.model; + + +import com.google.auto.value.AutoValue; +import org.sufficientlysecure.keychain.CertsModel; + + +@AutoValue +public abstract class Certification implements CertsModel { + public static final CertsModel.Factory FACTORY = + new CertsModel.Factory<>(AutoValue_Certification::new); + + public static final SelectVerifyingCertDetailsMapper CERT_DETAILS_MAPPER = + new SelectVerifyingCertDetailsMapper<>(AutoValue_Certification_CertDetails::new); + + @AutoValue + public static abstract class CertDetails implements CertsModel.SelectVerifyingCertDetailsModel { + + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index dbfede4aa..19641d835 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -294,13 +294,6 @@ public class KeychainContract { public static Uri buildCertsUri(long masterKeyId) { return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).appendPath(PATH_CERTS).build(); } - - public static Uri buildLinkedIdCertsUri(Uri uri, int rank) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)) - .appendPath(PATH_LINKED_IDS).appendPath(Integer.toString(rank)) - .appendPath(PATH_CERTS).build(); - } - } private KeychainContract() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 53cc79aad..f3b38f8b1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -66,7 +66,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe private static final int KEY_RING_PUBLIC = 203; private static final int KEY_RING_CERTS = 205; private static final int KEY_RING_LINKED_IDS = 207; - private static final int KEY_RING_LINKED_ID_CERTS = 208; private static final int KEY_RINGS_FIND_BY_EMAIL = 400; private static final int KEY_RINGS_FIND_BY_SUBKEY = 401; @@ -154,10 +153,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" + KeychainContract.PATH_LINKED_IDS, KEY_RING_LINKED_IDS); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" - + KeychainContract.PATH_LINKED_IDS + "/*/" - + KeychainContract.PATH_CERTS, - KEY_RING_LINKED_ID_CERTS); matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" + KeychainContract.PATH_PUBLIC, KEY_RING_PUBLIC); @@ -560,55 +555,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe break; } - case KEY_RING_CERTS: - case KEY_RING_LINKED_ID_CERTS: { - HashMap projectionMap = new HashMap<>(); - projectionMap.put(Certs._ID, Tables.CERTS + ".oid AS " + Certs._ID); - projectionMap.put(Certs.MASTER_KEY_ID, Tables.CERTS + "." + Certs.MASTER_KEY_ID); - projectionMap.put(Certs.RANK, Tables.CERTS + "." + Certs.RANK); - projectionMap.put(Certs.VERIFIED, Tables.CERTS + "." + Certs.VERIFIED); - projectionMap.put(Certs.TYPE, Tables.CERTS + "." + Certs.TYPE); - projectionMap.put(Certs.CREATION, Tables.CERTS + "." + Certs.CREATION); - projectionMap.put(Certs.KEY_ID_CERTIFIER, Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER); - projectionMap.put(Certs.DATA, Tables.CERTS + "." + Certs.DATA); - projectionMap.put(Certs.USER_ID, Tables.USER_PACKETS + "." + UserPackets.USER_ID); - projectionMap.put(Certs.SIGNER_UID, "signer." + UserPackets.USER_ID + " AS " + Certs.SIGNER_UID); - qb.setProjectionMap(projectionMap); - - qb.setTables(Tables.CERTS - + " JOIN " + Tables.USER_PACKETS + " ON (" - + Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = " - + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID - + " AND " - + Tables.CERTS + "." + Certs.RANK + " = " - + Tables.USER_PACKETS + "." + UserPackets.RANK - + ") LEFT JOIN " + Tables.USER_PACKETS + " AS signer ON (" - + Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER + " = " - + "signer." + UserPackets.MASTER_KEY_ID - + " AND " - + "signer." + Keys.RANK + " = 0" - + ")"); - - groupBy = Tables.CERTS + "." + Certs.RANK + ", " - + Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER; - - qb.appendWhere(Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - - if (match == KEY_RING_LINKED_ID_CERTS) { - qb.appendWhere(" AND " + Tables.USER_PACKETS + "." - + UserPackets.TYPE + " IS NOT NULL"); - - qb.appendWhere(" AND " + Tables.USER_PACKETS + "." - + UserPackets.RANK + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(3)); - } else { - qb.appendWhere(" AND " + Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL"); - } - - break; - } - default: { throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/LinkedIdViewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/LinkedIdViewFragment.java index c841a4ee7..bf5c0f997 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/LinkedIdViewFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/LinkedIdViewFragment.java @@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.ui.keyview; import java.io.IOException; import java.util.Collections; +import android.arch.lifecycle.LiveData; import android.content.Context; import android.content.Intent; import android.database.Cursor; @@ -54,6 +55,9 @@ import org.sufficientlysecure.keychain.linked.LinkedAttribute; import org.sufficientlysecure.keychain.linked.LinkedResource; import org.sufficientlysecure.keychain.linked.LinkedTokenResource; import org.sufficientlysecure.keychain.linked.UriAttribute; +import org.sufficientlysecure.keychain.livedata.CertificationDao; +import org.sufficientlysecure.keychain.livedata.GenericLiveData; +import org.sufficientlysecure.keychain.model.Certification.CertDetails; import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; @@ -407,17 +411,18 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements viewHolder.vButtonRetry.setOnClickListener(v -> verifyResource()); viewHolder.vButtonConfirm.setOnClickListener(v -> initiateCertifying()); - { - Bundle args = new Bundle(); - args.putParcelable(CertListWidget.ARG_URI, Certs.buildLinkedIdCertsUri(dataUri, lidRank)); - args.putBoolean(CertListWidget.ARG_IS_SECRET, isSecret); - getLoaderManager().initLoader(CertListWidget.LOADER_ID_LINKED_CERTS, - args, viewHolder.vLinkedCerts); - } + CertificationDao certificationDao = CertificationDao.getInstance(getContext()); + LiveData certDetailsLiveData = new GenericLiveData<>( + getContext(), null, () -> certificationDao.getVerifyingCertDetails(masterKeyId, lidRank)); + certDetailsLiveData.observe(this, this::onLoadCertDetails); return root; } + private void onLoadCertDetails(CertDetails certDetails) { + viewHolder.vLinkedCerts.setData(certDetails, isSecret); + } + void verifyResource() { // only one at a time (no sync needed, taskInProgress is only touched in ui thread) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertListWidget.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertListWidget.java index 7606f4ba6..f84c51367 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertListWidget.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertListWidget.java @@ -33,43 +33,14 @@ import android.widget.TextView; import android.widget.ViewAnimator; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.model.Certification.CertDetails; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; -public class CertListWidget extends ViewAnimator - implements LoaderManager.LoaderCallbacks { - - public static final int LOADER_ID_LINKED_CERTS = 38572; - - public static final String ARG_URI = "uri"; - public static final String ARG_IS_SECRET = "is_secret"; - - - // These are the rows that we will retrieve. - static final String[] CERTS_PROJECTION = new String[]{ - KeychainContract.Certs._ID, - KeychainContract.Certs.MASTER_KEY_ID, - KeychainContract.Certs.VERIFIED, - KeychainContract.Certs.TYPE, - KeychainContract.Certs.RANK, - KeychainContract.Certs.KEY_ID_CERTIFIER, - KeychainContract.Certs.USER_ID, - KeychainContract.Certs.SIGNER_UID, - KeychainContract.Certs.CREATION - }; - public static final int INDEX_MASTER_KEY_ID = 1; - public static final int INDEX_VERIFIED = 2; - public static final int INDEX_TYPE = 3; - public static final int INDEX_RANK = 4; - public static final int INDEX_KEY_ID_CERTIFIER = 5; - public static final int INDEX_USER_ID = 6; - public static final int INDEX_SIGNER_UID = 7; - public static final int INDEX_CREATION = 8; - +public class CertListWidget extends ViewAnimator { private TextView vCollapsed; private ListView vExpanded; private View vExpandButton; - private boolean mIsSecret; public CertListWidget(Context context, AttributeSet attrs) { super(context, attrs); @@ -105,41 +76,11 @@ public class CertListWidget extends ViewAnimator setDisplayedChild(expanded ? 1 : 0); } - @Override - public Loader onCreateLoader(int id, Bundle args) { - Uri uri = args.getParcelable(ARG_URI); - mIsSecret = args.getBoolean(ARG_IS_SECRET, false); - return new CursorLoader(getContext(), uri, - CERTS_PROJECTION, null, null, null); - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - - if (data == null || !data.moveToFirst()) { - return; - } - - // TODO support external certificates - Long certTime = null; - while (!data.isAfterLast()) { - - int verified = data.getInt(INDEX_VERIFIED); - long creation = data.getLong(INDEX_CREATION) * 1000; - - if (verified == Certs.VERIFIED_SECRET) { - if (certTime == null || certTime > creation) { - certTime = creation; - } - } - - data.moveToNext(); - } - - if (certTime != null) { + public void setData(CertDetails certDetails, boolean isSecret) { + if (certDetails != null) { CharSequence relativeTimeStr = DateUtils - .getRelativeTimeSpanString(certTime, System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_ALL); - if (mIsSecret) { + .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 + "."); @@ -150,9 +91,4 @@ public class CertListWidget extends ViewAnimator } - @Override - public void onLoaderReset(Loader loader) { - setVisibility(View.GONE); - } - } diff --git a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Certs.sq b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Certs.sq index 1553509aa..c80812b10 100644 --- a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Certs.sq +++ b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Certs.sq @@ -1,13 +1,20 @@ -- TODO implement. this is only here for reference in SQLDelight CREATE TABLE IF NOT EXISTS certs( - master_key_id INTEGER, - rank INTEGER, - key_id_certifier INTEGER, - type INTEGER, - verified INTEGER, - creation INTEGER, - data BLOB, + master_key_id INTEGER NOT NULL, + rank INTEGER NOT NULL, + key_id_certifier INTEGER NOT NULL, + type INTEGER NOT NULL, + verified INTEGER NOT NULL, + creation INTEGER NOT NULL, + data BLOB NOT NULL, 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 -); \ No newline at end of file +); + +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 + LIMIT 1; \ No newline at end of file