move loading of certs into CertificationDao
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<T> extends AsyncTaskLiveData<T> {
|
||||||
|
private GenericDataLoader<T> genericDataLoader;
|
||||||
|
|
||||||
|
public GenericLiveData(Context context, Uri uri, GenericDataLoader<T> genericDataLoader) {
|
||||||
|
super(context, uri);
|
||||||
|
this.genericDataLoader = genericDataLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected T asyncLoadData() {
|
||||||
|
return genericDataLoader.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface GenericDataLoader<T> {
|
||||||
|
T loadData();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<Certification> FACTORY =
|
||||||
|
new CertsModel.Factory<>(AutoValue_Certification::new);
|
||||||
|
|
||||||
|
public static final SelectVerifyingCertDetailsMapper<CertDetails> CERT_DETAILS_MAPPER =
|
||||||
|
new SelectVerifyingCertDetailsMapper<>(AutoValue_Certification_CertDetails::new);
|
||||||
|
|
||||||
|
@AutoValue
|
||||||
|
public static abstract class CertDetails implements CertsModel.SelectVerifyingCertDetailsModel {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -294,13 +294,6 @@ public class KeychainContract {
|
|||||||
public static Uri buildCertsUri(long masterKeyId) {
|
public static Uri buildCertsUri(long masterKeyId) {
|
||||||
return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).appendPath(PATH_CERTS).build();
|
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() {
|
private KeychainContract() {
|
||||||
|
|||||||
@@ -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_PUBLIC = 203;
|
||||||
private static final int KEY_RING_CERTS = 205;
|
private static final int KEY_RING_CERTS = 205;
|
||||||
private static final int KEY_RING_LINKED_IDS = 207;
|
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_EMAIL = 400;
|
||||||
private static final int KEY_RINGS_FIND_BY_SUBKEY = 401;
|
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 + "/*/"
|
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
||||||
+ KeychainContract.PATH_LINKED_IDS,
|
+ KeychainContract.PATH_LINKED_IDS,
|
||||||
KEY_RING_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 + "/*/"
|
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
||||||
+ KeychainContract.PATH_PUBLIC,
|
+ KeychainContract.PATH_PUBLIC,
|
||||||
KEY_RING_PUBLIC);
|
KEY_RING_PUBLIC);
|
||||||
@@ -560,55 +555,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case KEY_RING_CERTS:
|
|
||||||
case KEY_RING_LINKED_ID_CERTS: {
|
|
||||||
HashMap<String, String> 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: {
|
default: {
|
||||||
throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")");
|
throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.ui.keyview;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
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.LinkedResource;
|
||||||
import org.sufficientlysecure.keychain.linked.LinkedTokenResource;
|
import org.sufficientlysecure.keychain.linked.LinkedTokenResource;
|
||||||
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
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.LinkedVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
@@ -407,17 +411,18 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
|
|||||||
viewHolder.vButtonRetry.setOnClickListener(v -> verifyResource());
|
viewHolder.vButtonRetry.setOnClickListener(v -> verifyResource());
|
||||||
viewHolder.vButtonConfirm.setOnClickListener(v -> initiateCertifying());
|
viewHolder.vButtonConfirm.setOnClickListener(v -> initiateCertifying());
|
||||||
|
|
||||||
{
|
CertificationDao certificationDao = CertificationDao.getInstance(getContext());
|
||||||
Bundle args = new Bundle();
|
LiveData<CertDetails> certDetailsLiveData = new GenericLiveData<>(
|
||||||
args.putParcelable(CertListWidget.ARG_URI, Certs.buildLinkedIdCertsUri(dataUri, lidRank));
|
getContext(), null, () -> certificationDao.getVerifyingCertDetails(masterKeyId, lidRank));
|
||||||
args.putBoolean(CertListWidget.ARG_IS_SECRET, isSecret);
|
certDetailsLiveData.observe(this, this::onLoadCertDetails);
|
||||||
getLoaderManager().initLoader(CertListWidget.LOADER_ID_LINKED_CERTS,
|
|
||||||
args, viewHolder.vLinkedCerts);
|
|
||||||
}
|
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onLoadCertDetails(CertDetails certDetails) {
|
||||||
|
viewHolder.vLinkedCerts.setData(certDetails, isSecret);
|
||||||
|
}
|
||||||
|
|
||||||
void verifyResource() {
|
void verifyResource() {
|
||||||
|
|
||||||
// only one at a time (no sync needed, taskInProgress is only touched in ui thread)
|
// only one at a time (no sync needed, taskInProgress is only touched in ui thread)
|
||||||
|
|||||||
@@ -33,43 +33,14 @@ import android.widget.TextView;
|
|||||||
import android.widget.ViewAnimator;
|
import android.widget.ViewAnimator;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.model.Certification.CertDetails;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||||
|
|
||||||
public class CertListWidget extends ViewAnimator
|
public class CertListWidget extends ViewAnimator {
|
||||||
implements LoaderManager.LoaderCallbacks<Cursor> {
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
private TextView vCollapsed;
|
private TextView vCollapsed;
|
||||||
private ListView vExpanded;
|
private ListView vExpanded;
|
||||||
private View vExpandButton;
|
private View vExpandButton;
|
||||||
private boolean mIsSecret;
|
|
||||||
|
|
||||||
public CertListWidget(Context context, AttributeSet attrs) {
|
public CertListWidget(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
@@ -105,41 +76,11 @@ public class CertListWidget extends ViewAnimator
|
|||||||
setDisplayedChild(expanded ? 1 : 0);
|
setDisplayedChild(expanded ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void setData(CertDetails certDetails, boolean isSecret) {
|
||||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
if (certDetails != null) {
|
||||||
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<Cursor> 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) {
|
|
||||||
CharSequence relativeTimeStr = DateUtils
|
CharSequence relativeTimeStr = DateUtils
|
||||||
.getRelativeTimeSpanString(certTime, System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_ALL);
|
.getRelativeTimeSpanString(certDetails.creation(), System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_ALL);
|
||||||
if (mIsSecret) {
|
if (isSecret) {
|
||||||
vCollapsed.setText("You created this identity " + relativeTimeStr + ".");
|
vCollapsed.setText("You created this identity " + relativeTimeStr + ".");
|
||||||
} else {
|
} else {
|
||||||
vCollapsed.setText("You verified and confirmed this identity " + relativeTimeStr + ".");
|
vCollapsed.setText("You verified and confirmed this identity " + relativeTimeStr + ".");
|
||||||
@@ -150,9 +91,4 @@ public class CertListWidget extends ViewAnimator
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoaderReset(Loader<Cursor> loader) {
|
|
||||||
setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
-- TODO implement. this is only here for reference in SQLDelight
|
-- TODO implement. this is only here for reference in SQLDelight
|
||||||
CREATE TABLE IF NOT EXISTS certs(
|
CREATE TABLE IF NOT EXISTS certs(
|
||||||
master_key_id INTEGER,
|
master_key_id INTEGER NOT NULL,
|
||||||
rank INTEGER,
|
rank INTEGER NOT NULL,
|
||||||
key_id_certifier INTEGER,
|
key_id_certifier INTEGER NOT NULL,
|
||||||
type INTEGER,
|
type INTEGER NOT NULL,
|
||||||
verified INTEGER,
|
verified INTEGER NOT NULL,
|
||||||
creation INTEGER,
|
creation INTEGER NOT NULL,
|
||||||
data BLOB,
|
data BLOB NOT NULL,
|
||||||
PRIMARY KEY(master_key_id, rank, key_id_certifier),
|
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) 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
|
-- FOREIGN KEY(master_key_id, rank) REFERENCES user_packets(master_key_id, rank) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
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;
|
||||||
Reference in New Issue
Block a user