extract linked id loading from ContentProvider
This commit is contained in:
parent
9ad29318e8
commit
377bf55b70
|
@ -0,0 +1,32 @@
|
||||||
|
package org.sufficientlysecure.keychain.model;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.auto.value.AutoValue;
|
||||||
|
import org.sufficientlysecure.keychain.UserPacketsModel;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||||
|
|
||||||
|
|
||||||
|
@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);
|
||||||
|
|
||||||
|
@AutoValue
|
||||||
|
public static abstract class UserId implements SelectUserIdsByMasterKeyIdModel {
|
||||||
|
public boolean isVerified() {
|
||||||
|
Integer verified = verified();
|
||||||
|
return verified != null && verified == Certs.VERIFIED_SECRET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoValue
|
||||||
|
public static abstract class UserAttribute implements SelectUserAttributesByTypeAndMasterKeyIdModel {
|
||||||
|
public boolean isVerified() {
|
||||||
|
Integer verified = verified();
|
||||||
|
return verified != null && verified == Certs.VERIFIED_SECRET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -109,7 +109,6 @@ public class KeychainContract {
|
||||||
|
|
||||||
public static final String PATH_PUBLIC = "public";
|
public static final String PATH_PUBLIC = "public";
|
||||||
public static final String PATH_USER_IDS = "user_ids";
|
public static final String PATH_USER_IDS = "user_ids";
|
||||||
public static final String PATH_LINKED_IDS = "linked_ids";
|
|
||||||
public static final String PATH_KEYS = "keys";
|
public static final String PATH_KEYS = "keys";
|
||||||
public static final String PATH_CERTS = "certs";
|
public static final String PATH_CERTS = "certs";
|
||||||
|
|
||||||
|
@ -253,15 +252,6 @@ public class KeychainContract {
|
||||||
public static Uri buildUserIdsUri(Uri uri) {
|
public static Uri buildUserIdsUri(Uri uri) {
|
||||||
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_USER_IDS).build();
|
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_USER_IDS).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri buildLinkedIdsUri(long masterKeyId) {
|
|
||||||
return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).appendPath(PATH_LINKED_IDS).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Uri buildLinkedIdsUri(Uri uri) {
|
|
||||||
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_LINKED_IDS).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Certs implements CertsColumns, BaseColumns {
|
public static class Certs implements CertsColumns, BaseColumns {
|
||||||
|
|
|
@ -25,7 +25,6 @@ import java.util.List;
|
||||||
|
|
||||||
import android.arch.persistence.db.SupportSQLiteDatabase;
|
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||||
import android.content.ContentProvider;
|
import android.content.ContentProvider;
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.UriMatcher;
|
import android.content.UriMatcher;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
@ -39,7 +38,6 @@ import android.text.TextUtils;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer;
|
import org.sufficientlysecure.keychain.model.AutocryptPeer;
|
||||||
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
|
@ -64,7 +62,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||||
private static final int KEY_RING_USER_IDS = 202;
|
private static final int KEY_RING_USER_IDS = 202;
|
||||||
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_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;
|
||||||
|
@ -140,9 +137,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||||
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
||||||
+ KeychainContract.PATH_USER_IDS,
|
+ KeychainContract.PATH_USER_IDS,
|
||||||
KEY_RING_USER_IDS);
|
KEY_RING_USER_IDS);
|
||||||
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
|
||||||
+ KeychainContract.PATH_LINKED_IDS,
|
|
||||||
KEY_RING_LINKED_IDS);
|
|
||||||
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);
|
||||||
|
@ -473,8 +467,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||||
}
|
}
|
||||||
|
|
||||||
case KEY_RINGS_USER_IDS:
|
case KEY_RINGS_USER_IDS:
|
||||||
case KEY_RING_USER_IDS:
|
case KEY_RING_USER_IDS: {
|
||||||
case KEY_RING_LINKED_IDS: {
|
|
||||||
HashMap<String, String> projectionMap = new HashMap<>();
|
HashMap<String, String> projectionMap = new HashMap<>();
|
||||||
projectionMap.put(UserPackets._ID, Tables.USER_PACKETS + ".oid AS _id");
|
projectionMap.put(UserPackets._ID, Tables.USER_PACKETS + ".oid AS _id");
|
||||||
projectionMap.put(UserPackets.MASTER_KEY_ID, Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID);
|
projectionMap.put(UserPackets.MASTER_KEY_ID, Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID);
|
||||||
|
@ -502,15 +495,10 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe
|
||||||
groupBy = Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID
|
groupBy = Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID
|
||||||
+ ", " + Tables.USER_PACKETS + "." + UserPackets.RANK;
|
+ ", " + Tables.USER_PACKETS + "." + UserPackets.RANK;
|
||||||
|
|
||||||
if (match == KEY_RING_LINKED_IDS) {
|
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL");
|
||||||
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " = "
|
|
||||||
+ WrappedUserAttribute.UAT_URI_ATTRIBUTE);
|
|
||||||
} else {
|
|
||||||
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are searching for a particular keyring's ids, add where
|
// If we are searching for a particular keyring's ids, add where
|
||||||
if (match == KEY_RING_USER_IDS || match == KEY_RING_LINKED_IDS) {
|
if (match == KEY_RING_USER_IDS) {
|
||||||
qb.appendWhere(" AND ");
|
qb.appendWhere(" AND ");
|
||||||
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = ");
|
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = ");
|
||||||
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
@ -42,6 +43,7 @@ import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||||
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
||||||
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.UserPackets;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
|
||||||
|
@ -179,7 +181,7 @@ public class ViewKeyAdvUserIdsFragment extends LoaderFragment implements
|
||||||
private void showUserIdInfo(final int position) {
|
private void showUserIdInfo(final int position) {
|
||||||
|
|
||||||
final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position);
|
final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position);
|
||||||
final int isVerified = mUserIdsAdapter.getIsVerified(position);
|
final boolean isVerified = mUserIdsAdapter.getIsVerified(position) == Certs.VERIFIED_SECRET;
|
||||||
|
|
||||||
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
|
DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
|
@ -35,12 +35,11 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.ViewHolder;
|
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.ViewHolder;
|
||||||
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.AutocryptPeerInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.IdentityInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.LinkedIdInfo;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.LinkedIdInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.UserIdInfo;
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.UserIdInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.AutocryptPeerInfo;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||||
import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker;
|
import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker;
|
||||||
|
@ -158,7 +157,7 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
public void bind(Context context, LinkedIdInfo info, boolean isSecret) {
|
public void bind(Context context, LinkedIdInfo info, boolean isSecret) {
|
||||||
bindVerified(context, info, isSecret);
|
bindVerified(context, info, isSecret);
|
||||||
|
|
||||||
UriAttribute uriAttribute = info.getUriAttribute();
|
UriAttribute uriAttribute = info.getLinkedAttribute();
|
||||||
bind(context, uriAttribute);
|
bind(context, uriAttribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,19 +177,12 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
|
|
||||||
private void bindVerified(Context context, IdentityInfo info, boolean isSecret) {
|
private void bindVerified(Context context, IdentityInfo info, boolean isSecret) {
|
||||||
if (!isSecret) {
|
if (!isSecret) {
|
||||||
switch (info.getVerified()) {
|
if (info.isVerified()) {
|
||||||
case Certs.VERIFIED_SECRET:
|
KeyFormattingUtils.setStatusImage(context, vVerified,
|
||||||
KeyFormattingUtils.setStatusImage(context, vVerified,
|
null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||||
null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
} else {
|
||||||
break;
|
KeyFormattingUtils.setStatusImage(context, vVerified,
|
||||||
case Certs.VERIFIED_SELF:
|
null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||||
KeyFormattingUtils.setStatusImage(context, vVerified,
|
|
||||||
null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
KeyFormattingUtils.setStatusImage(context, vVerified,
|
|
||||||
null, State.INVALID, KeyFormattingUtils.DEFAULT_COLOR);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,11 @@
|
||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui.adapter;
|
package org.sufficientlysecure.keychain.ui.adapter;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.net.Uri;
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.content.CursorLoader;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -33,7 +31,6 @@ import android.widget.ViewAnimator;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||||
|
@ -184,14 +181,4 @@ public class UserIdsAdapter extends UserAttributesAdapter {
|
||||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||||
return mInflater.inflate(R.layout.view_key_adv_user_id_item, null);
|
return mInflater.inflate(R.layout.view_key_adv_user_id_item, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't show revoked user ids, irrelevant for average users
|
|
||||||
public static final String USER_IDS_WHERE = UserPackets.IS_REVOKED + " = 0";
|
|
||||||
|
|
||||||
public static CursorLoader createLoader(Context context, Uri dataUri) {
|
|
||||||
Uri baseUri = UserPackets.buildUserIdsUri(dataUri);
|
|
||||||
return new CursorLoader(context, baseUri,
|
|
||||||
UserIdsAdapter.USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui.dialog;
|
package org.sufficientlysecure.keychain.ui.dialog;
|
||||||
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
@ -24,7 +25,6 @@ import android.os.Bundle;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
|
||||||
|
|
||||||
public class UserIdInfoDialogFragment extends DialogFragment {
|
public class UserIdInfoDialogFragment extends DialogFragment {
|
||||||
private static final String ARG_IS_REVOKED = "is_revoked";
|
private static final String ARG_IS_REVOKED = "is_revoked";
|
||||||
|
@ -33,11 +33,11 @@ public class UserIdInfoDialogFragment extends DialogFragment {
|
||||||
/**
|
/**
|
||||||
* Creates new instance of this dialog fragment
|
* Creates new instance of this dialog fragment
|
||||||
*/
|
*/
|
||||||
public static UserIdInfoDialogFragment newInstance(boolean isRevoked, int isVerified) {
|
public static UserIdInfoDialogFragment newInstance(boolean isRevoked, boolean isVerified) {
|
||||||
UserIdInfoDialogFragment frag = new UserIdInfoDialogFragment();
|
UserIdInfoDialogFragment frag = new UserIdInfoDialogFragment();
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putBoolean(ARG_IS_REVOKED, isRevoked);
|
args.putBoolean(ARG_IS_REVOKED, isRevoked);
|
||||||
args.putInt(ARG_IS_VERIFIED, isVerified);
|
args.putBoolean(ARG_IS_VERIFIED, isVerified);
|
||||||
|
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public class UserIdInfoDialogFragment extends DialogFragment {
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
|
|
||||||
int isVerified = getArguments().getInt(ARG_IS_VERIFIED);
|
boolean isVerified = getArguments().getBoolean(ARG_IS_VERIFIED);
|
||||||
boolean isRevoked = getArguments().getBoolean(ARG_IS_REVOKED);
|
boolean isRevoked = getArguments().getBoolean(ARG_IS_REVOKED);
|
||||||
|
|
||||||
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
|
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
|
||||||
|
@ -62,19 +62,12 @@ public class UserIdInfoDialogFragment extends DialogFragment {
|
||||||
title = getString(R.string.user_id_info_revoked_title);
|
title = getString(R.string.user_id_info_revoked_title);
|
||||||
message = getString(R.string.user_id_info_revoked_text);
|
message = getString(R.string.user_id_info_revoked_text);
|
||||||
} else {
|
} else {
|
||||||
switch (isVerified) {
|
if (isVerified) {
|
||||||
case KeychainContract.Certs.VERIFIED_SECRET:
|
title = getString(R.string.user_id_info_certified_title);
|
||||||
title = getString(R.string.user_id_info_certified_title);
|
message = getString(R.string.user_id_info_certified_text);
|
||||||
message = getString(R.string.user_id_info_certified_text);
|
} else {
|
||||||
break;
|
title = getString(R.string.user_id_info_uncertified_title);
|
||||||
case KeychainContract.Certs.VERIFIED_SELF:
|
message = getString(R.string.user_id_info_uncertified_text);
|
||||||
title = getString(R.string.user_id_info_uncertified_title);
|
|
||||||
message = getString(R.string.user_id_info_uncertified_text);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
title = getString(R.string.user_id_info_invalid_title);
|
|
||||||
message = getString(R.string.user_id_info_invalid_text);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,15 +18,12 @@
|
||||||
package org.sufficientlysecure.keychain.ui.keyview;
|
package org.sufficientlysecure.keychain.ui.keyview;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import android.arch.lifecycle.LiveData;
|
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.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -37,10 +34,7 @@ import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.FragmentActivity;
|
import android.support.v4.app.FragmentActivity;
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.support.v4.app.FragmentManager.OnBackStackChangedListener;
|
import android.support.v4.app.FragmentManager.OnBackStackChangedListener;
|
||||||
import android.support.v4.app.LoaderManager;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v4.content.CursorLoader;
|
|
||||||
import android.support.v4.content.Loader;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -62,15 +56,13 @@ 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;
|
||||||
import org.sufficientlysecure.keychain.provider.KeyRepository;
|
import org.sufficientlysecure.keychain.provider.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
|
||||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
|
||||||
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
|
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
|
|
||||||
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment.ViewHolder.VerifyState;
|
import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment.ViewHolder.VerifyState;
|
||||||
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao;
|
||||||
|
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.LinkedIdInfo;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
|
@ -81,14 +73,11 @@ import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
||||||
public class LinkedIdViewFragment extends CryptoOperationFragment implements
|
public class LinkedIdViewFragment extends CryptoOperationFragment implements OnBackStackChangedListener {
|
||||||
LoaderManager.LoaderCallbacks<Cursor>, OnBackStackChangedListener {
|
|
||||||
|
|
||||||
private static final String ARG_DATA_URI = "data_uri";
|
|
||||||
private static final String ARG_LID_RANK = "rank";
|
private static final String ARG_LID_RANK = "rank";
|
||||||
private static final String ARG_IS_SECRET = "verified";
|
private static final String ARG_IS_SECRET = "verified";
|
||||||
private static final String ARG_MASTER_KEY_ID = "master_key_id";
|
private static final String ARG_MASTER_KEY_ID = "master_key_id";
|
||||||
private static final int LOADER_ID_LINKED_ID = 1;
|
|
||||||
|
|
||||||
private long masterKeyId;
|
private long masterKeyId;
|
||||||
private boolean isSecret;
|
private boolean isSecret;
|
||||||
|
@ -98,16 +87,14 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
|
||||||
|
|
||||||
private AsyncTask taskInProgress;
|
private AsyncTask taskInProgress;
|
||||||
|
|
||||||
private Uri dataUri;
|
|
||||||
private ViewHolder viewHolder;
|
private ViewHolder viewHolder;
|
||||||
private int lidRank;
|
private int lidRank;
|
||||||
private long certifyKeyId;
|
private long certifyKeyId;
|
||||||
|
|
||||||
public static LinkedIdViewFragment newInstance(Uri dataUri, int rank, boolean isSecret, long masterKeyId) {
|
public static LinkedIdViewFragment newInstance(long masterKeyId, int rank, boolean isSecret) {
|
||||||
LinkedIdViewFragment frag = new LinkedIdViewFragment();
|
LinkedIdViewFragment frag = new LinkedIdViewFragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putParcelable(ARG_DATA_URI, dataUri);
|
|
||||||
args.putInt(ARG_LID_RANK, rank);
|
args.putInt(ARG_LID_RANK, rank);
|
||||||
args.putBoolean(ARG_IS_SECRET, isSecret);
|
args.putBoolean(ARG_IS_SECRET, isSecret);
|
||||||
args.putLong(ARG_MASTER_KEY_ID, masterKeyId);
|
args.putLong(ARG_MASTER_KEY_ID, masterKeyId);
|
||||||
|
@ -127,57 +114,27 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
Bundle args = getArguments();
|
Bundle args = getArguments();
|
||||||
dataUri = args.getParcelable(ARG_DATA_URI);
|
|
||||||
lidRank = args.getInt(ARG_LID_RANK);
|
lidRank = args.getInt(ARG_LID_RANK);
|
||||||
|
|
||||||
isSecret = args.getBoolean(ARG_IS_SECRET);
|
isSecret = args.getBoolean(ARG_IS_SECRET);
|
||||||
masterKeyId = args.getLong(ARG_MASTER_KEY_ID);
|
masterKeyId = args.getLong(ARG_MASTER_KEY_ID);
|
||||||
|
|
||||||
getLoaderManager().initLoader(LOADER_ID_LINKED_ID, null, this);
|
IdentityDao identityDao = IdentityDao.getInstance(getContext());
|
||||||
|
GenericLiveData<LinkedIdInfo> uriAttributeLiveData =
|
||||||
|
new GenericLiveData<>(getContext(), null, () -> identityDao.getLinkedIdInfo(masterKeyId, lidRank));
|
||||||
|
uriAttributeLiveData.observe(this, this::onLinkedIdInfoLoaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void onLinkedIdInfoLoaded(LinkedIdInfo linkedIdInfo) {
|
||||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
if (linkedIdInfo == null) {
|
||||||
switch (id) {
|
Timber.e("error loading identity");
|
||||||
case LOADER_ID_LINKED_ID:
|
Notify.create(getActivity(), "Error loading linked identity!",
|
||||||
return new CursorLoader(getContext(), dataUri,
|
Notify.LENGTH_LONG, Style.ERROR).show();
|
||||||
UserIdsAdapter.USER_PACKETS_PROJECTION,
|
finishFragment();
|
||||||
Tables.USER_PACKETS + "." + UserPackets.RANK
|
return;
|
||||||
+ " = " + Integer.toString(lidRank), null, null);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
loadIdentity(linkedIdInfo.getLinkedAttribute(), linkedIdInfo.isVerified());
|
||||||
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
|
|
||||||
switch (loader.getId()) {
|
|
||||||
case LOADER_ID_LINKED_ID:
|
|
||||||
|
|
||||||
// Nothing to load means break if we are *expected* to load
|
|
||||||
if (!cursor.moveToFirst()) {
|
|
||||||
// Or just ignore, this is probably some intermediate state during certify
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
int certStatus = cursor.getInt(UserIdsAdapter.INDEX_VERIFIED);
|
|
||||||
|
|
||||||
byte[] data = cursor.getBlob(UserIdsAdapter.INDEX_ATTRIBUTE_DATA);
|
|
||||||
UriAttribute linkedId = LinkedAttribute.fromAttributeData(data);
|
|
||||||
|
|
||||||
loadIdentity(linkedId, certStatus);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
Timber.e(e, "error parsing identity");
|
|
||||||
Notify.create(getActivity(), "Error parsing identity!",
|
|
||||||
Notify.LENGTH_LONG, Style.ERROR).show();
|
|
||||||
finishFragment();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finishFragment() {
|
public void finishFragment() {
|
||||||
|
@ -188,28 +145,19 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadIdentity(UriAttribute linkedId, int certStatus) {
|
private void loadIdentity(LinkedAttribute linkedId, boolean isVerified) {
|
||||||
this.linkedId = linkedId;
|
this.linkedId = linkedId;
|
||||||
|
|
||||||
if (this.linkedId instanceof LinkedAttribute) {
|
LinkedResource res = ((LinkedAttribute) this.linkedId).mResource;
|
||||||
LinkedResource res = ((LinkedAttribute) this.linkedId).mResource;
|
linkedResource = (LinkedTokenResource) res;
|
||||||
linkedResource = (LinkedTokenResource) res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSecret) {
|
if (!isSecret) {
|
||||||
switch (certStatus) {
|
if (isVerified) {
|
||||||
case Certs.VERIFIED_SECRET:
|
KeyFormattingUtils.setStatusImage(getContext(), viewHolder.mLinkedIdHolder.vVerified,
|
||||||
KeyFormattingUtils.setStatusImage(getContext(), viewHolder.mLinkedIdHolder.vVerified,
|
null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||||
null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
} else {
|
||||||
break;
|
KeyFormattingUtils.setStatusImage(getContext(), viewHolder.mLinkedIdHolder.vVerified,
|
||||||
case Certs.VERIFIED_SELF:
|
null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||||
KeyFormattingUtils.setStatusImage(getContext(), viewHolder.mLinkedIdHolder.vVerified,
|
|
||||||
null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
KeyFormattingUtils.setStatusImage(getContext(), viewHolder.mLinkedIdHolder.vVerified,
|
|
||||||
null, State.INVALID, KeyFormattingUtils.DEFAULT_COLOR);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
viewHolder.mLinkedIdHolder.vVerified.setImageResource(R.drawable.octo_link_24dp);
|
viewHolder.mLinkedIdHolder.vVerified.setImageResource(R.drawable.octo_link_24dp);
|
||||||
|
@ -219,13 +167,6 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
|
||||||
|
|
||||||
setShowVerifying(false);
|
setShowVerifying(false);
|
||||||
|
|
||||||
// no resource, nothing further we can do…
|
|
||||||
if (linkedResource == null) {
|
|
||||||
viewHolder.vButtonView.setVisibility(View.GONE);
|
|
||||||
viewHolder.vButtonVerify.setVisibility(View.GONE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (linkedResource.isViewable()) {
|
if (linkedResource.isViewable()) {
|
||||||
viewHolder.vButtonView.setVisibility(View.VISIBLE);
|
viewHolder.vButtonView.setVisibility(View.VISIBLE);
|
||||||
viewHolder.vButtonView.setOnClickListener(v -> {
|
viewHolder.vButtonView.setOnClickListener(v -> {
|
||||||
|
@ -241,11 +182,6 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoaderReset(Loader<Cursor> loader) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ViewHolder {
|
static class ViewHolder {
|
||||||
private final View vButtonView;
|
private final View vButtonView;
|
||||||
private final ViewAnimator vVerifyingContainer;
|
private final ViewAnimator vVerifyingContainer;
|
||||||
|
@ -395,25 +331,29 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
|
||||||
View root = inflater.inflate(R.layout.linked_id_view_fragment, null);
|
View root = inflater.inflate(R.layout.linked_id_view_fragment, superContainer, false);
|
||||||
|
Context context = getContext();
|
||||||
|
if (context == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
|
||||||
viewHolder = new ViewHolder(root);
|
viewHolder = new ViewHolder(root);
|
||||||
root.setTag(viewHolder);
|
root.setTag(viewHolder);
|
||||||
|
|
||||||
((ImageView) root.findViewById(R.id.status_icon_verified))
|
((ImageView) root.findViewById(R.id.status_icon_verified))
|
||||||
.setColorFilter(ContextCompat.getColor(getContext(), R.color.android_green_light),
|
.setColorFilter(ContextCompat.getColor(context, R.color.android_green_light),
|
||||||
PorterDuff.Mode.SRC_IN);
|
PorterDuff.Mode.SRC_IN);
|
||||||
((ImageView) root.findViewById(R.id.status_icon_invalid))
|
((ImageView) root.findViewById(R.id.status_icon_invalid))
|
||||||
.setColorFilter(ContextCompat.getColor(getContext(), R.color.android_red_light),
|
.setColorFilter(ContextCompat.getColor(context, R.color.android_red_light),
|
||||||
PorterDuff.Mode.SRC_IN);
|
PorterDuff.Mode.SRC_IN);
|
||||||
|
|
||||||
viewHolder.vButtonVerify.setOnClickListener(v -> verifyResource());
|
viewHolder.vButtonVerify.setOnClickListener(v -> verifyResource());
|
||||||
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());
|
CertificationDao certificationDao = CertificationDao.getInstance(context);
|
||||||
LiveData<CertDetails> certDetailsLiveData = new GenericLiveData<>(
|
LiveData<CertDetails> certDetailsLiveData = new GenericLiveData<>(
|
||||||
getContext(), null, () -> certificationDao.getVerifyingCertDetails(masterKeyId, lidRank));
|
context, null, () -> certificationDao.getVerifyingCertDetails(masterKeyId, lidRank));
|
||||||
certDetailsLiveData.observe(this, this::onLoadCertDetails);
|
certDetailsLiveData.observe(this, this::onLoadCertDetails);
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
|
|
|
@ -23,7 +23,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
@ -33,63 +33,40 @@ import android.graphics.drawable.Drawable;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
|
import com.squareup.sqldelight.SqlDelightQuery;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.sufficientlysecure.keychain.linked.LinkedAttribute;
|
import org.sufficientlysecure.keychain.linked.LinkedAttribute;
|
||||||
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
import org.sufficientlysecure.keychain.linked.UriAttribute;
|
||||||
import org.sufficientlysecure.keychain.model.AutocryptPeer;
|
import org.sufficientlysecure.keychain.model.AutocryptPeer;
|
||||||
|
import org.sufficientlysecure.keychain.model.UserPacket;
|
||||||
|
import org.sufficientlysecure.keychain.model.UserPacket.UserAttribute;
|
||||||
|
import org.sufficientlysecure.keychain.model.UserPacket.UserId;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
||||||
import org.sufficientlysecure.keychain.provider.AutocryptPeerDao;
|
import org.sufficientlysecure.keychain.provider.AutocryptPeerDao;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.PackageIconGetter;
|
import org.sufficientlysecure.keychain.ui.util.PackageIconGetter;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
||||||
public class IdentityDao {
|
public class IdentityDao {
|
||||||
private static final String[] USER_PACKETS_PROJECTION = new String[]{
|
private final SupportSQLiteDatabase db;
|
||||||
UserPackets._ID,
|
|
||||||
UserPackets.TYPE,
|
|
||||||
UserPackets.USER_ID,
|
|
||||||
UserPackets.ATTRIBUTE_DATA,
|
|
||||||
UserPackets.RANK,
|
|
||||||
UserPackets.VERIFIED,
|
|
||||||
UserPackets.IS_PRIMARY,
|
|
||||||
UserPackets.IS_REVOKED,
|
|
||||||
UserPackets.NAME,
|
|
||||||
UserPackets.EMAIL,
|
|
||||||
UserPackets.COMMENT,
|
|
||||||
};
|
|
||||||
private static final int INDEX_ID = 0;
|
|
||||||
private static final int INDEX_TYPE = 1;
|
|
||||||
private static final int INDEX_USER_ID = 2;
|
|
||||||
private static final int INDEX_ATTRIBUTE_DATA = 3;
|
|
||||||
private static final int INDEX_RANK = 4;
|
|
||||||
private static final int INDEX_VERIFIED = 5;
|
|
||||||
private static final int INDEX_IS_PRIMARY = 6;
|
|
||||||
private static final int INDEX_IS_REVOKED = 7;
|
|
||||||
private static final int INDEX_NAME = 8;
|
|
||||||
private static final int INDEX_EMAIL = 9;
|
|
||||||
private static final int INDEX_COMMENT = 10;
|
|
||||||
|
|
||||||
private static final String USER_IDS_WHERE = UserPackets.IS_REVOKED + " = 0";
|
|
||||||
|
|
||||||
|
|
||||||
private final ContentResolver contentResolver;
|
|
||||||
private final PackageIconGetter packageIconGetter;
|
private final PackageIconGetter packageIconGetter;
|
||||||
private final PackageManager packageManager;
|
private final PackageManager packageManager;
|
||||||
private final AutocryptPeerDao autocryptPeerDao;
|
private final AutocryptPeerDao autocryptPeerDao;
|
||||||
|
|
||||||
static IdentityDao getInstance(Context context) {
|
public static IdentityDao getInstance(Context context) {
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
SupportSQLiteDatabase db = new KeychainDatabase(context).getWritableDatabase();
|
||||||
PackageManager packageManager = context.getPackageManager();
|
PackageManager packageManager = context.getPackageManager();
|
||||||
PackageIconGetter iconGetter = PackageIconGetter.getInstance(context);
|
PackageIconGetter iconGetter = PackageIconGetter.getInstance(context);
|
||||||
AutocryptPeerDao autocryptPeerDao = AutocryptPeerDao.getInstance(context);
|
AutocryptPeerDao autocryptPeerDao = AutocryptPeerDao.getInstance(context);
|
||||||
return new IdentityDao(contentResolver, packageManager, iconGetter, autocryptPeerDao);
|
return new IdentityDao(db, packageManager, iconGetter, autocryptPeerDao);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IdentityDao(ContentResolver contentResolver, PackageManager packageManager, PackageIconGetter iconGetter,
|
private IdentityDao(SupportSQLiteDatabase db,
|
||||||
|
PackageManager packageManager, PackageIconGetter iconGetter,
|
||||||
AutocryptPeerDao autocryptPeerDao) {
|
AutocryptPeerDao autocryptPeerDao) {
|
||||||
|
this.db = db;
|
||||||
this.packageManager = packageManager;
|
this.packageManager = packageManager;
|
||||||
this.contentResolver = contentResolver;
|
|
||||||
this.packageIconGetter = iconGetter;
|
this.packageIconGetter = iconGetter;
|
||||||
this.autocryptPeerDao = autocryptPeerDao;
|
this.autocryptPeerDao = autocryptPeerDao;
|
||||||
}
|
}
|
||||||
|
@ -156,73 +133,70 @@ public class IdentityDao {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadLinkedIds(ArrayList<IdentityInfo> identities, long masterKeyId) {
|
private void loadLinkedIds(ArrayList<IdentityInfo> identities, long masterKeyId) {
|
||||||
Cursor cursor = contentResolver.query(UserPackets.buildLinkedIdsUri(masterKeyId),
|
SqlDelightQuery query = UserPacket.FACTORY.selectUserAttributesByTypeAndMasterKeyId(
|
||||||
USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null);
|
(long) WrappedUserAttribute.UAT_URI_ATTRIBUTE, masterKeyId);
|
||||||
if (cursor == null) {
|
try (Cursor cursor = db.query(query)) {
|
||||||
Timber.e("Error loading key items!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
int rank = cursor.getInt(INDEX_RANK);
|
UserAttribute userAttribute = UserPacket.USER_ATTRIBUTE_MAPPER.map(cursor);
|
||||||
int verified = cursor.getInt(INDEX_VERIFIED);
|
|
||||||
boolean isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0;
|
|
||||||
|
|
||||||
byte[] data = cursor.getBlob(INDEX_ATTRIBUTE_DATA);
|
LinkedIdInfo linkedIdInfo = parseLinkedIdInfo(userAttribute);
|
||||||
try {
|
identities.add(linkedIdInfo);
|
||||||
UriAttribute uriAttribute = LinkedAttribute.fromAttributeData(data);
|
|
||||||
if (uriAttribute instanceof LinkedAttribute) {
|
|
||||||
LinkedIdInfo identityInfo = LinkedIdInfo.create(rank, verified, isPrimary, uriAttribute);
|
|
||||||
identities.add(identityInfo);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Timber.e(e, "Failed parsing uri attribute");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadUserIds(ArrayList<IdentityInfo> identities, long masterKeyId) {
|
public LinkedIdInfo getLinkedIdInfo(long masterKeyId, int rank) {
|
||||||
Cursor cursor = contentResolver.query(UserPackets.buildUserIdsUri(masterKeyId),
|
SqlDelightQuery query = UserPacket.FACTORY.selectSpecificUserAttribute(
|
||||||
USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null);
|
(long) WrappedUserAttribute.UAT_URI_ATTRIBUTE, masterKeyId, rank);
|
||||||
if (cursor == null) {
|
try (Cursor cursor = db.query(query)) {
|
||||||
Timber.e("Error loading key items!");
|
if (cursor.moveToFirst()) {
|
||||||
return;
|
UserAttribute userAttribute = UserPacket.USER_ATTRIBUTE_MAPPER.map(cursor);
|
||||||
|
|
||||||
|
return parseLinkedIdInfo(userAttribute);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private LinkedIdInfo parseLinkedIdInfo(UserAttribute userAttribute) {
|
||||||
try {
|
try {
|
||||||
|
UriAttribute uriAttribute = LinkedAttribute.fromAttributeData(userAttribute.attribute_data());
|
||||||
|
if (uriAttribute instanceof LinkedAttribute) {
|
||||||
|
return LinkedIdInfo.create(userAttribute.rank(),
|
||||||
|
userAttribute.isVerified(), userAttribute.is_primary(), (LinkedAttribute) uriAttribute);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Timber.e(e, "Failed parsing uri attribute");
|
||||||
|
}
|
||||||
|
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()) {
|
while (cursor.moveToNext()) {
|
||||||
int rank = cursor.getInt(INDEX_RANK);
|
UserId userId = UserPacket.USER_ID_MAPPER.map(cursor);
|
||||||
int verified = cursor.getInt(INDEX_VERIFIED);
|
|
||||||
boolean isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0;
|
|
||||||
|
|
||||||
if (!cursor.isNull(INDEX_NAME) || !cursor.isNull(INDEX_EMAIL)) {
|
if (userId.name() != null || userId.email() != null) {
|
||||||
String name = cursor.getString(INDEX_NAME);
|
IdentityInfo identityInfo = UserIdInfo.create(
|
||||||
String email = cursor.getString(INDEX_EMAIL);
|
userId.rank(), userId.isVerified(), userId.is_primary(), userId.name(), userId.email(), userId.comment());
|
||||||
String comment = cursor.getString(INDEX_COMMENT);
|
|
||||||
|
|
||||||
IdentityInfo identityInfo = UserIdInfo.create(rank, verified, isPrimary, name, email, comment);
|
|
||||||
identities.add(identityInfo);
|
identities.add(identityInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IdentityInfo {
|
public interface IdentityInfo {
|
||||||
int getRank();
|
int getRank();
|
||||||
int getVerified();
|
boolean isVerified();
|
||||||
boolean isPrimary();
|
boolean isPrimary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public abstract static class UserIdInfo implements IdentityInfo {
|
public abstract static class UserIdInfo implements IdentityInfo {
|
||||||
public abstract int getRank();
|
public abstract int getRank();
|
||||||
public abstract int getVerified();
|
public abstract boolean isVerified();
|
||||||
public abstract boolean isPrimary();
|
public abstract boolean isPrimary();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -232,29 +206,29 @@ public class IdentityDao {
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract String getComment();
|
public abstract String getComment();
|
||||||
|
|
||||||
static UserIdInfo create(int rank, int verified, boolean isPrimary, String name, String email,
|
static UserIdInfo create(int rank, boolean isVerified, boolean isPrimary, String name, String email,
|
||||||
String comment) {
|
String comment) {
|
||||||
return new AutoValue_IdentityDao_UserIdInfo(rank, verified, isPrimary, name, email, comment);
|
return new AutoValue_IdentityDao_UserIdInfo(rank, isVerified, isPrimary, name, email, comment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public abstract static class LinkedIdInfo implements IdentityInfo {
|
public abstract static class LinkedIdInfo implements IdentityInfo {
|
||||||
public abstract int getRank();
|
public abstract int getRank();
|
||||||
public abstract int getVerified();
|
public abstract boolean isVerified();
|
||||||
public abstract boolean isPrimary();
|
public abstract boolean isPrimary();
|
||||||
|
|
||||||
public abstract UriAttribute getUriAttribute();
|
public abstract LinkedAttribute getLinkedAttribute();
|
||||||
|
|
||||||
static LinkedIdInfo create(int rank, int verified, boolean isPrimary, UriAttribute uriAttribute) {
|
static LinkedIdInfo create(int rank, boolean isVerified, boolean isPrimary, LinkedAttribute linkedAttribute) {
|
||||||
return new AutoValue_IdentityDao_LinkedIdInfo(rank, verified, isPrimary, uriAttribute);
|
return new AutoValue_IdentityDao_LinkedIdInfo(rank, isVerified, isPrimary, linkedAttribute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AutoValue
|
@AutoValue
|
||||||
public abstract static class AutocryptPeerInfo implements IdentityInfo {
|
public abstract static class AutocryptPeerInfo implements IdentityInfo {
|
||||||
public abstract int getRank();
|
public abstract int getRank();
|
||||||
public abstract int getVerified();
|
public abstract boolean isVerified();
|
||||||
public abstract boolean isPrimary();
|
public abstract boolean isPrimary();
|
||||||
|
|
||||||
public abstract String getIdentity();
|
public abstract String getIdentity();
|
||||||
|
@ -268,13 +242,13 @@ public class IdentityDao {
|
||||||
|
|
||||||
static AutocryptPeerInfo create(UserIdInfo userIdInfo, String autocryptPeer, String packageName,
|
static AutocryptPeerInfo create(UserIdInfo userIdInfo, String autocryptPeer, String packageName,
|
||||||
Drawable appIcon, Intent autocryptPeerIntent) {
|
Drawable appIcon, Intent autocryptPeerIntent) {
|
||||||
return new AutoValue_IdentityDao_AutocryptPeerInfo(userIdInfo.getRank(), userIdInfo.getVerified(),
|
return new AutoValue_IdentityDao_AutocryptPeerInfo(userIdInfo.getRank(), userIdInfo.isVerified(),
|
||||||
userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo, autocryptPeerIntent);
|
userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo, autocryptPeerIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AutocryptPeerInfo create(String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) {
|
static AutocryptPeerInfo create(String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) {
|
||||||
return new AutoValue_IdentityDao_AutocryptPeerInfo(
|
return new AutoValue_IdentityDao_AutocryptPeerInfo(
|
||||||
0, Certs.VERIFIED_SELF, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent);
|
0, false, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,20 +18,17 @@
|
||||||
package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
package org.sufficientlysecure.keychain.ui.keyview.presenter;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import android.arch.lifecycle.LiveData;
|
import android.arch.lifecycle.LiveData;
|
||||||
import android.arch.lifecycle.Observer;
|
import android.arch.lifecycle.Observer;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.provider.AutocryptPeerDao;
|
import org.sufficientlysecure.keychain.provider.AutocryptPeerDao;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.IdentityClickListener;
|
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.IdentityClickListener;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment;
|
||||||
|
@ -114,17 +111,14 @@ public class IdentitiesPresenter implements Observer<List<IdentityInfo>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showLinkedId(final LinkedIdInfo info) {
|
private void showLinkedId(final LinkedIdInfo info) {
|
||||||
Uri dataUri = UserPackets.buildLinkedIdsUri(KeyRings.buildGenericKeyRingUri(masterKeyId));
|
LinkedIdViewFragment frag = LinkedIdViewFragment.newInstance(masterKeyId, info.getRank(), isSecret);
|
||||||
LinkedIdViewFragment frag = LinkedIdViewFragment.newInstance(dataUri, info.getRank(), isSecret, masterKeyId);
|
|
||||||
|
|
||||||
viewKeyMvpView.switchToFragment(frag, "linked_id");
|
viewKeyMvpView.switchToFragment(frag, "linked_id");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showUserIdInfo(UserIdInfo info) {
|
private void showUserIdInfo(UserIdInfo info) {
|
||||||
if (!isSecret) {
|
if (!isSecret) {
|
||||||
final int isVerified = info.getVerified();
|
UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(false, info.isVerified());
|
||||||
|
|
||||||
UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(false, isVerified);
|
|
||||||
viewKeyMvpView.showDialogFragment(dialogFragment, "userIdInfoDialog");
|
viewKeyMvpView.showDialogFragment(dialogFragment, "userIdInfoDialog");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -727,8 +727,6 @@
|
||||||
<string name="user_id_info_certified_text">"This identity has been confirmed by you."</string>
|
<string name="user_id_info_certified_text">"This identity has been confirmed by you."</string>
|
||||||
<string name="user_id_info_uncertified_title">"Not confirmed"</string>
|
<string name="user_id_info_uncertified_title">"Not confirmed"</string>
|
||||||
<string name="user_id_info_uncertified_text">"This identity has not been confirmed yet. You cannot be sure if the identity really corresponds to a specific person."</string>
|
<string name="user_id_info_uncertified_text">"This identity has not been confirmed yet. You cannot be sure if the identity really corresponds to a specific person."</string>
|
||||||
<string name="user_id_info_invalid_title">"Invalid"</string>
|
|
||||||
<string name="user_id_info_invalid_text">"Something is wrong with this identity!"</string>
|
|
||||||
|
|
||||||
<!-- Key trust -->
|
<!-- Key trust -->
|
||||||
<string name="key_trust_no_cloud_evidence">"No proof from the Internet on this key’s trustworthiness."</string>
|
<string name="key_trust_no_cloud_evidence">"No proof from the Internet on this key’s trustworthiness."</string>
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
import java.lang.Integer;
|
||||||
|
|
||||||
-- 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 NOT NULL,
|
master_key_id INTEGER NOT NULL,
|
||||||
rank INTEGER NOT NULL,
|
rank INTEGER NOT NULL,
|
||||||
key_id_certifier INTEGER NOT NULL,
|
key_id_certifier INTEGER NOT NULL,
|
||||||
type INTEGER NOT NULL,
|
type INTEGER NOT NULL,
|
||||||
verified INTEGER NOT NULL,
|
verified INTEGER AS Integer NOT NULL,
|
||||||
creation INTEGER NOT NULL,
|
creation INTEGER NOT NULL,
|
||||||
data BLOB NOT NULL,
|
data BLOB NOT NULL,
|
||||||
PRIMARY KEY(master_key_id, rank, key_id_certifier),
|
PRIMARY KEY(master_key_id, rank, key_id_certifier),
|
||||||
|
|
|
@ -1,15 +1,35 @@
|
||||||
|
import java.lang.Integer;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS user_packets(
|
CREATE TABLE IF NOT EXISTS user_packets(
|
||||||
master_key_id INTEGER,
|
master_key_id INTEGER NOT NULL,
|
||||||
|
rank INTEGER AS Integer NOT NULL,
|
||||||
type INTEGER,
|
type INTEGER,
|
||||||
user_id TEXT,
|
user_id TEXT,
|
||||||
name TEXT,
|
name TEXT,
|
||||||
email TEXT,
|
email TEXT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
attribute_data BLOB,
|
attribute_data BLOB,
|
||||||
is_primary INTEGER,
|
is_primary INTEGER AS Boolean NOT NULL,
|
||||||
is_revoked INTEGER,
|
is_revoked INTEGER AS Boolean NOT NULL,
|
||||||
rank INTEGER,
|
|
||||||
PRIMARY KEY(master_key_id, rank),
|
PRIMARY KEY(master_key_id, rank),
|
||||||
FOREIGN KEY(master_key_id) REFERENCES
|
FOREIGN KEY(master_key_id) REFERENCES
|
||||||
keyrings_public(master_key_id) ON DELETE CASCADE
|
keyrings_public(master_key_id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
selectUserIdsByMasterKeyId:
|
||||||
|
SELECT user_packets.master_key_id, user_packets.rank, user_id, name, email, comment, is_primary, is_revoked, certs.verified
|
||||||
|
FROM user_packets
|
||||||
|
LEFT JOIN certs ON ( user_packets.master_key_id = certs.master_key_id AND user_packets.rank = certs.rank AND certs.verified > 0 )
|
||||||
|
WHERE user_packets.type IS NULL AND user_packets.is_revoked = 0 AND user_packets.master_key_id = ?;
|
||||||
|
|
||||||
|
selectUserAttributesByTypeAndMasterKeyId:
|
||||||
|
SELECT user_packets.master_key_id, user_packets.rank, attribute_data, is_primary, is_revoked, certs.verified
|
||||||
|
FROM user_packets
|
||||||
|
LEFT JOIN certs ON ( user_packets.master_key_id = certs.master_key_id AND user_packets.rank = certs.rank AND certs.verified > 0 )
|
||||||
|
WHERE user_packets.type = ? AND user_packets.is_revoked = 0 AND user_packets.master_key_id = ?;
|
||||||
|
|
||||||
|
selectSpecificUserAttribute:
|
||||||
|
SELECT user_packets.master_key_id, user_packets.rank, attribute_data, is_primary, is_revoked, certs.verified
|
||||||
|
FROM user_packets
|
||||||
|
LEFT JOIN certs ON ( user_packets.master_key_id = certs.master_key_id AND user_packets.rank = certs.rank AND certs.verified > 0 )
|
||||||
|
WHERE user_packets.type = ? AND user_packets.master_key_id = ? AND user_packets.rank = ?;
|
||||||
|
|
Loading…
Reference in a new issue