diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/UserPacket.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/UserPacket.java new file mode 100644 index 000000000..7a9291a97 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/model/UserPacket.java @@ -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 FACTORY = new Factory<>(AutoValue_UserPacket::new); + public static final SelectUserIdsByMasterKeyIdMapper USER_ID_MAPPER = + FACTORY.selectUserIdsByMasterKeyIdMapper(AutoValue_UserPacket_UserId::new); + public static final SelectUserAttributesByTypeAndMasterKeyIdMapper 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; + } + } +} 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 85e79df25..696d6e1d4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -109,7 +109,6 @@ public class KeychainContract { public static final String PATH_PUBLIC = "public"; 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_CERTS = "certs"; @@ -253,15 +252,6 @@ public class KeychainContract { public static Uri buildUserIdsUri(Uri uri) { 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 { 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 045e8ccef..40398f741 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -25,7 +25,6 @@ import java.util.List; import android.arch.persistence.db.SupportSQLiteDatabase; import android.content.ContentProvider; -import android.content.ContentResolver; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; @@ -39,7 +38,6 @@ import android.text.TextUtils; import org.sufficientlysecure.keychain.Constants; 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.KeyRingData; 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_PUBLIC = 203; 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_SUBKEY = 401; @@ -140,9 +137,6 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" + KeychainContract.PATH_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 + "/*/" + KeychainContract.PATH_PUBLIC, KEY_RING_PUBLIC); @@ -473,8 +467,7 @@ public class KeychainProvider extends ContentProvider implements SimpleContentRe } case KEY_RINGS_USER_IDS: - case KEY_RING_USER_IDS: - case KEY_RING_LINKED_IDS: { + case KEY_RING_USER_IDS: { HashMap projectionMap = new HashMap<>(); projectionMap.put(UserPackets._ID, Tables.USER_PACKETS + ".oid AS _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 + ", " + Tables.USER_PACKETS + "." + UserPackets.RANK; - if (match == KEY_RING_LINKED_IDS) { - qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " = " - + WrappedUserAttribute.UAT_URI_ATTRIBUTE); - } else { - qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL"); - } + qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL"); // 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(Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = "); qb.appendWhereEscapeString(uri.getPathSegments().get(1)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java index a0811e8b5..6e51ee7a0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java @@ -17,6 +17,7 @@ package org.sufficientlysecure.keychain.ui; + import android.content.Intent; import android.database.Cursor; import android.net.Uri; @@ -42,6 +43,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; @@ -179,7 +181,7 @@ public class ViewKeyAdvUserIdsFragment extends LoaderFragment implements private void showUserIdInfo(final int 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() { public void run() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java index 5500b1674..860e2bf22 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java @@ -35,12 +35,11 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.R; 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.keyview.loader.IdentityDao.AutocryptPeerInfo; 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.UserIdInfo; -import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityDao.AutocryptPeerInfo; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker; @@ -158,7 +157,7 @@ public class IdentityAdapter extends RecyclerView.Adapter { public void bind(Context context, LinkedIdInfo info, boolean isSecret) { bindVerified(context, info, isSecret); - UriAttribute uriAttribute = info.getUriAttribute(); + UriAttribute uriAttribute = info.getLinkedAttribute(); bind(context, uriAttribute); } @@ -178,19 +177,12 @@ public class IdentityAdapter extends RecyclerView.Adapter { private void bindVerified(Context context, IdentityInfo info, boolean isSecret) { if (!isSecret) { - switch (info.getVerified()) { - case Certs.VERIFIED_SECRET: - KeyFormattingUtils.setStatusImage(context, vVerified, - null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR); - break; - case Certs.VERIFIED_SELF: - KeyFormattingUtils.setStatusImage(context, vVerified, - null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR); - break; - default: - KeyFormattingUtils.setStatusImage(context, vVerified, - null, State.INVALID, KeyFormattingUtils.DEFAULT_COLOR); - break; + if (info.isVerified()) { + KeyFormattingUtils.setStatusImage(context, vVerified, + null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR); + } else { + KeyFormattingUtils.setStatusImage(context, vVerified, + null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR); } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index e48b79f1e..8550a5eca 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -17,13 +17,11 @@ package org.sufficientlysecure.keychain.ui.adapter; -import android.app.Activity; + import android.content.Context; import android.database.Cursor; import android.graphics.Typeface; -import android.net.Uri; import android.support.annotation.Nullable; -import android.support.v4.content.CursorLoader; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -33,7 +31,6 @@ import android.widget.ViewAnimator; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; 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) { 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); - } - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/UserIdInfoDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/UserIdInfoDialogFragment.java index db20f7d1f..3d6122a68 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/UserIdInfoDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/UserIdInfoDialogFragment.java @@ -17,6 +17,7 @@ package org.sufficientlysecure.keychain.ui.dialog; + import android.app.Activity; import android.app.Dialog; import android.content.DialogInterface; @@ -24,7 +25,6 @@ import android.os.Bundle; import android.support.v4.app.DialogFragment; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract; public class UserIdInfoDialogFragment extends DialogFragment { 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 */ - public static UserIdInfoDialogFragment newInstance(boolean isRevoked, int isVerified) { + public static UserIdInfoDialogFragment newInstance(boolean isRevoked, boolean isVerified) { UserIdInfoDialogFragment frag = new UserIdInfoDialogFragment(); Bundle args = new Bundle(); args.putBoolean(ARG_IS_REVOKED, isRevoked); - args.putInt(ARG_IS_VERIFIED, isVerified); + args.putBoolean(ARG_IS_VERIFIED, isVerified); frag.setArguments(args); @@ -51,7 +51,7 @@ public class UserIdInfoDialogFragment extends DialogFragment { public Dialog onCreateDialog(Bundle savedInstanceState) { 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); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); @@ -62,19 +62,12 @@ public class UserIdInfoDialogFragment extends DialogFragment { title = getString(R.string.user_id_info_revoked_title); message = getString(R.string.user_id_info_revoked_text); } else { - switch (isVerified) { - case KeychainContract.Certs.VERIFIED_SECRET: - title = getString(R.string.user_id_info_certified_title); - message = getString(R.string.user_id_info_certified_text); - break; - case KeychainContract.Certs.VERIFIED_SELF: - 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; + if (isVerified) { + title = getString(R.string.user_id_info_certified_title); + message = getString(R.string.user_id_info_certified_text); + } else { + title = getString(R.string.user_id_info_uncertified_title); + message = getString(R.string.user_id_info_uncertified_text); } } 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 bf5c0f997..902003d41 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 @@ -18,15 +18,12 @@ 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; import android.graphics.PorterDuff; -import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; @@ -37,10 +34,7 @@ import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager.OnBackStackChangedListener; -import android.support.v4.app.LoaderManager; 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.View; 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.pgp.exception.PgpKeyNotFoundException; 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.CertifyAction; 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.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.State; import org.sufficientlysecure.keychain.ui.util.Notify; @@ -81,14 +73,11 @@ import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner; import timber.log.Timber; -public class LinkedIdViewFragment extends CryptoOperationFragment implements - LoaderManager.LoaderCallbacks, OnBackStackChangedListener { +public class LinkedIdViewFragment extends CryptoOperationFragment implements OnBackStackChangedListener { - private static final String ARG_DATA_URI = "data_uri"; private static final String ARG_LID_RANK = "rank"; private static final String ARG_IS_SECRET = "verified"; private static final String ARG_MASTER_KEY_ID = "master_key_id"; - private static final int LOADER_ID_LINKED_ID = 1; private long masterKeyId; private boolean isSecret; @@ -98,16 +87,14 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements private AsyncTask taskInProgress; - private Uri dataUri; private ViewHolder viewHolder; private int lidRank; 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(); Bundle args = new Bundle(); - args.putParcelable(ARG_DATA_URI, dataUri); args.putInt(ARG_LID_RANK, rank); args.putBoolean(ARG_IS_SECRET, isSecret); args.putLong(ARG_MASTER_KEY_ID, masterKeyId); @@ -127,57 +114,27 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements super.onCreate(savedInstanceState); Bundle args = getArguments(); - dataUri = args.getParcelable(ARG_DATA_URI); lidRank = args.getInt(ARG_LID_RANK); isSecret = args.getBoolean(ARG_IS_SECRET); masterKeyId = args.getLong(ARG_MASTER_KEY_ID); - getLoaderManager().initLoader(LOADER_ID_LINKED_ID, null, this); - + IdentityDao identityDao = IdentityDao.getInstance(getContext()); + GenericLiveData uriAttributeLiveData = + new GenericLiveData<>(getContext(), null, () -> identityDao.getLinkedIdInfo(masterKeyId, lidRank)); + uriAttributeLiveData.observe(this, this::onLinkedIdInfoLoaded); } - @Override - public Loader onCreateLoader(int id, Bundle args) { - switch (id) { - case LOADER_ID_LINKED_ID: - return new CursorLoader(getContext(), dataUri, - UserIdsAdapter.USER_PACKETS_PROJECTION, - Tables.USER_PACKETS + "." + UserPackets.RANK - + " = " + Integer.toString(lidRank), null, null); - default: - return null; + private void onLinkedIdInfoLoaded(LinkedIdInfo linkedIdInfo) { + if (linkedIdInfo == null) { + Timber.e("error loading identity"); + Notify.create(getActivity(), "Error loading linked identity!", + Notify.LENGTH_LONG, Style.ERROR).show(); + finishFragment(); + return; } - } - @Override - public void onLoadFinished(Loader 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; - } + loadIdentity(linkedIdInfo.getLinkedAttribute(), linkedIdInfo.isVerified()); } 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; - if (this.linkedId instanceof LinkedAttribute) { - LinkedResource res = ((LinkedAttribute) this.linkedId).mResource; - linkedResource = (LinkedTokenResource) res; - } + LinkedResource res = ((LinkedAttribute) this.linkedId).mResource; + linkedResource = (LinkedTokenResource) res; if (!isSecret) { - switch (certStatus) { - case Certs.VERIFIED_SECRET: - KeyFormattingUtils.setStatusImage(getContext(), viewHolder.mLinkedIdHolder.vVerified, - null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR); - break; - case Certs.VERIFIED_SELF: - 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; + if (isVerified) { + KeyFormattingUtils.setStatusImage(getContext(), viewHolder.mLinkedIdHolder.vVerified, + null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR); + } else { + KeyFormattingUtils.setStatusImage(getContext(), viewHolder.mLinkedIdHolder.vVerified, + null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR); } } else { viewHolder.mLinkedIdHolder.vVerified.setImageResource(R.drawable.octo_link_24dp); @@ -219,13 +167,6 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements 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()) { viewHolder.vButtonView.setVisibility(View.VISIBLE); viewHolder.vButtonView.setOnClickListener(v -> { @@ -241,11 +182,6 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements } - @Override - public void onLoaderReset(Loader loader) { - - } - static class ViewHolder { private final View vButtonView; private final ViewAnimator vVerifyingContainer; @@ -395,25 +331,29 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements @Override 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); root.setTag(viewHolder); ((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); ((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); viewHolder.vButtonVerify.setOnClickListener(v -> verifyResource()); viewHolder.vButtonRetry.setOnClickListener(v -> verifyResource()); viewHolder.vButtonConfirm.setOnClickListener(v -> initiateCertifying()); - CertificationDao certificationDao = CertificationDao.getInstance(getContext()); + CertificationDao certificationDao = CertificationDao.getInstance(context); LiveData certDetailsLiveData = new GenericLiveData<>( - getContext(), null, () -> certificationDao.getVerifyingCertDetails(masterKeyId, lidRank)); + context, null, () -> certificationDao.getVerifyingCertDetails(masterKeyId, lidRank)); certDetailsLiveData.observe(this, this::onLoadCertDetails); return root; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityDao.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityDao.java index fe6609e5f..f3a39cccf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityDao.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityDao.java @@ -23,7 +23,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import android.content.ContentResolver; +import android.arch.persistence.db.SupportSQLiteDatabase; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -33,63 +33,40 @@ import android.graphics.drawable.Drawable; import android.support.annotation.Nullable; import com.google.auto.value.AutoValue; +import com.squareup.sqldelight.SqlDelightQuery; import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.linked.LinkedAttribute; import org.sufficientlysecure.keychain.linked.UriAttribute; 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.KeychainContract.Certs; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; +import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.ui.util.PackageIconGetter; import timber.log.Timber; public class IdentityDao { - private static final String[] USER_PACKETS_PROJECTION = new String[]{ - 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 SupportSQLiteDatabase db; private final PackageIconGetter packageIconGetter; private final PackageManager packageManager; private final AutocryptPeerDao autocryptPeerDao; - static IdentityDao getInstance(Context context) { - ContentResolver contentResolver = context.getContentResolver(); + public static IdentityDao getInstance(Context context) { + SupportSQLiteDatabase db = new KeychainDatabase(context).getWritableDatabase(); PackageManager packageManager = context.getPackageManager(); PackageIconGetter iconGetter = PackageIconGetter.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) { + this.db = db; this.packageManager = packageManager; - this.contentResolver = contentResolver; this.packageIconGetter = iconGetter; this.autocryptPeerDao = autocryptPeerDao; } @@ -156,73 +133,70 @@ public class IdentityDao { } private void loadLinkedIds(ArrayList identities, long masterKeyId) { - Cursor cursor = contentResolver.query(UserPackets.buildLinkedIdsUri(masterKeyId), - USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null); - if (cursor == null) { - Timber.e("Error loading key items!"); - return; - } - - try { + SqlDelightQuery query = UserPacket.FACTORY.selectUserAttributesByTypeAndMasterKeyId( + (long) WrappedUserAttribute.UAT_URI_ATTRIBUTE, masterKeyId); + try (Cursor cursor = db.query(query)) { while (cursor.moveToNext()) { - int rank = cursor.getInt(INDEX_RANK); - int verified = cursor.getInt(INDEX_VERIFIED); - boolean isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0; + UserAttribute userAttribute = UserPacket.USER_ATTRIBUTE_MAPPER.map(cursor); - byte[] data = cursor.getBlob(INDEX_ATTRIBUTE_DATA); - try { - 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"); - } + LinkedIdInfo linkedIdInfo = parseLinkedIdInfo(userAttribute); + identities.add(linkedIdInfo); } - } finally { - cursor.close(); } } - private void loadUserIds(ArrayList identities, long masterKeyId) { - Cursor cursor = contentResolver.query(UserPackets.buildUserIdsUri(masterKeyId), - USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null); - if (cursor == null) { - Timber.e("Error loading key items!"); - return; + public LinkedIdInfo getLinkedIdInfo(long masterKeyId, int rank) { + SqlDelightQuery query = UserPacket.FACTORY.selectSpecificUserAttribute( + (long) WrappedUserAttribute.UAT_URI_ATTRIBUTE, masterKeyId, rank); + try (Cursor cursor = db.query(query)) { + if (cursor.moveToFirst()) { + UserAttribute userAttribute = UserPacket.USER_ATTRIBUTE_MAPPER.map(cursor); + + return parseLinkedIdInfo(userAttribute); + } } + return null; + } + @Nullable + private LinkedIdInfo parseLinkedIdInfo(UserAttribute userAttribute) { 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 identities, long masterKeyId) { + SqlDelightQuery query = UserPacket.FACTORY.selectUserIdsByMasterKeyId(masterKeyId); + try (Cursor cursor = db.query(query)) { while (cursor.moveToNext()) { - int rank = cursor.getInt(INDEX_RANK); - int verified = cursor.getInt(INDEX_VERIFIED); - boolean isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0; + UserId userId = UserPacket.USER_ID_MAPPER.map(cursor); - if (!cursor.isNull(INDEX_NAME) || !cursor.isNull(INDEX_EMAIL)) { - String name = cursor.getString(INDEX_NAME); - String email = cursor.getString(INDEX_EMAIL); - String comment = cursor.getString(INDEX_COMMENT); - - IdentityInfo identityInfo = UserIdInfo.create(rank, verified, isPrimary, name, email, comment); + if (userId.name() != null || userId.email() != null) { + IdentityInfo identityInfo = UserIdInfo.create( + userId.rank(), userId.isVerified(), userId.is_primary(), userId.name(), userId.email(), userId.comment()); identities.add(identityInfo); } } - } finally { - cursor.close(); } } public interface IdentityInfo { int getRank(); - int getVerified(); + boolean isVerified(); boolean isPrimary(); } @AutoValue public abstract static class UserIdInfo implements IdentityInfo { public abstract int getRank(); - public abstract int getVerified(); + public abstract boolean isVerified(); public abstract boolean isPrimary(); @Nullable @@ -232,29 +206,29 @@ public class IdentityDao { @Nullable 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) { - return new AutoValue_IdentityDao_UserIdInfo(rank, verified, isPrimary, name, email, comment); + return new AutoValue_IdentityDao_UserIdInfo(rank, isVerified, isPrimary, name, email, comment); } } @AutoValue public abstract static class LinkedIdInfo implements IdentityInfo { public abstract int getRank(); - public abstract int getVerified(); + public abstract boolean isVerified(); public abstract boolean isPrimary(); - public abstract UriAttribute getUriAttribute(); + public abstract LinkedAttribute getLinkedAttribute(); - static LinkedIdInfo create(int rank, int verified, boolean isPrimary, UriAttribute uriAttribute) { - return new AutoValue_IdentityDao_LinkedIdInfo(rank, verified, isPrimary, uriAttribute); + static LinkedIdInfo create(int rank, boolean isVerified, boolean isPrimary, LinkedAttribute linkedAttribute) { + return new AutoValue_IdentityDao_LinkedIdInfo(rank, isVerified, isPrimary, linkedAttribute); } } @AutoValue public abstract static class AutocryptPeerInfo implements IdentityInfo { public abstract int getRank(); - public abstract int getVerified(); + public abstract boolean isVerified(); public abstract boolean isPrimary(); public abstract String getIdentity(); @@ -268,13 +242,13 @@ public class IdentityDao { static AutocryptPeerInfo create(UserIdInfo userIdInfo, String autocryptPeer, String packageName, 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); } static AutocryptPeerInfo create(String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) { return new AutoValue_IdentityDao_AutocryptPeerInfo( - 0, Certs.VERIFIED_SELF, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent); + 0, false, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java index 566868d34..9bb3815b4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java @@ -18,20 +18,17 @@ package org.sufficientlysecure.keychain.ui.keyview.presenter; -import java.io.IOException; import java.util.List; import android.arch.lifecycle.LiveData; import android.arch.lifecycle.Observer; import android.content.Context; import android.content.Intent; -import android.net.Uri; import android.support.annotation.Nullable; import android.view.View; import org.sufficientlysecure.keychain.provider.AutocryptPeerDao; 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.IdentityClickListener; import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; @@ -114,17 +111,14 @@ public class IdentitiesPresenter implements Observer> { } private void showLinkedId(final LinkedIdInfo info) { - Uri dataUri = UserPackets.buildLinkedIdsUri(KeyRings.buildGenericKeyRingUri(masterKeyId)); - LinkedIdViewFragment frag = LinkedIdViewFragment.newInstance(dataUri, info.getRank(), isSecret, masterKeyId); + LinkedIdViewFragment frag = LinkedIdViewFragment.newInstance(masterKeyId, info.getRank(), isSecret); viewKeyMvpView.switchToFragment(frag, "linked_id"); } private void showUserIdInfo(UserIdInfo info) { if (!isSecret) { - final int isVerified = info.getVerified(); - - UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(false, isVerified); + UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(false, info.isVerified()); viewKeyMvpView.showDialogFragment(dialogFragment, "userIdInfoDialog"); } } diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 60c8f19d5..1b3a4aa17 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -727,8 +727,6 @@ "This identity has been confirmed by you." "Not confirmed" "This identity has not been confirmed yet. You cannot be sure if the identity really corresponds to a specific person." - "Invalid" - "Something is wrong with this identity!" "No proof from the Internet on this key’s trustworthiness." diff --git a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Certs.sq b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Certs.sq index 98c284b52..377135d4c 100644 --- a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Certs.sq +++ b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/Certs.sq @@ -1,10 +1,12 @@ +import java.lang.Integer; + -- TODO implement. this is only here for reference in SQLDelight CREATE TABLE IF NOT EXISTS certs( master_key_id INTEGER NOT NULL, rank INTEGER NOT NULL, key_id_certifier INTEGER NOT NULL, type INTEGER NOT NULL, - verified INTEGER NOT NULL, + verified INTEGER AS Integer NOT NULL, creation INTEGER NOT NULL, data BLOB NOT NULL, PRIMARY KEY(master_key_id, rank, key_id_certifier), diff --git a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/UserPackets.sq b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/UserPackets.sq index 75b5fe4a1..062869b34 100644 --- a/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/UserPackets.sq +++ b/OpenKeychain/src/main/sqldelight/org/sufficientlysecure/keychain/UserPackets.sq @@ -1,15 +1,35 @@ +import java.lang.Integer; + 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, user_id TEXT, name TEXT, email TEXT, comment TEXT, attribute_data BLOB, - is_primary INTEGER, - is_revoked INTEGER, - rank INTEGER, + is_primary INTEGER AS Boolean NOT NULL, + is_revoked INTEGER AS Boolean NOT NULL, PRIMARY KEY(master_key_id, rank), FOREIGN KEY(master_key_id) REFERENCES keyrings_public(master_key_id) ON DELETE CASCADE -); \ No newline at end of file +); + +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 = ?;