From 22063cdd6eca32e83e7937a849e70185a1faee2a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 22 Mar 2015 03:34:34 +0100 Subject: improve status reporting in yubikey dialogue --- .../keychain/ui/ViewKeyYubikeyFragment.java | 113 +++++++++++++++++++-- .../src/main/res/layout/view_key_yubikey.xml | 11 +- OpenKeychain/src/main/res/values/strings.xml | 4 + 3 files changed, 114 insertions(+), 14 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java index 7df791fbf..f60b6f299 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java @@ -1,35 +1,48 @@ package org.sufficientlysecure.keychain.ui; +import java.nio.ByteBuffer; +import java.util.Arrays; + import android.content.Intent; +import android.database.Cursor; import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.widget.Button; import android.widget.TextView; import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; +import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -public class ViewKeyYubikeyFragment extends Fragment { - +public class ViewKeyYubikeyFragment extends Fragment + implements LoaderCallbacks { public static final String ARG_FINGERPRINT = "fingerprint"; public static final String ARG_USER_ID = "user_id"; public static final String ARG_AID = "aid"; - private byte[] mFingerprints; + private byte[][] mFingerprints; private String mUserId; private byte[] mAid; + private long mMasterKeyId; + private Button vButton; + private TextView vStatus; public static ViewKeyYubikeyFragment newInstance(byte[] fingerprints, String userId, byte[] aid) { @@ -50,10 +63,19 @@ public class ViewKeyYubikeyFragment extends Fragment { super.onCreate(savedInstanceState); Bundle args = getArguments(); - mFingerprints = args.getByteArray(ARG_FINGERPRINT); + ByteBuffer buf = ByteBuffer.wrap(args.getByteArray(ARG_FINGERPRINT)); + mFingerprints = new byte[buf.remaining()/40][]; + for (int i = 0; i < mFingerprints.length; i++) { + mFingerprints[i] = new byte[20]; + buf.get(mFingerprints[i]); + } mUserId = args.getString(ARG_USER_ID); mAid = args.getByteArray(ARG_AID); + mMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mFingerprints[0]); + + getLoaderManager().initLoader(0, null, this); + } @Override @@ -64,21 +86,23 @@ public class ViewKeyYubikeyFragment extends Fragment { TextView vUserId = (TextView) view.findViewById(R.id.yubikey_userid); String serno = Hex.toHexString(mAid, 10, 4); - vSerNo.setText("Serial N° " + serno); + vSerNo.setText(getString(R.string.yubikey_serno, serno)); if (!mUserId.isEmpty()) { - vUserId.setText("Key holder: " + mUserId); + vUserId.setText(getString(R.string.yubikey_key_holder, mUserId)); } else { - vUserId.setText("Key holder: " + ""); + vUserId.setText(getString(R.string.yubikey_key_holder_unset)); } - view.findViewById(R.id.button_import).setOnClickListener(new OnClickListener() { + vButton = (Button) view.findViewById(R.id.button_bind); + vButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { promoteToSecretKey(); } }); + vStatus = (TextView) view.findViewById(R.id.yubikey_status); return view; } @@ -111,10 +135,8 @@ public class ViewKeyYubikeyFragment extends Fragment { intent.setAction(KeychainIntentService.ACTION_PROMOTE_KEYRING); - long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mFingerprints); - Bundle data = new Bundle(); - data.putLong(KeychainIntentService.PROMOTE_MASTER_KEY_ID, masterKeyId); + data.putLong(KeychainIntentService.PROMOTE_MASTER_KEY_ID, mMasterKeyId); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Create a new Messenger for the communication back @@ -126,4 +148,73 @@ public class ViewKeyYubikeyFragment extends Fragment { } + public static final String[] PROJECTION = new String[]{ + Keys._ID, + Keys.KEY_ID, + Keys.RANK, + Keys.HAS_SECRET, + Keys.FINGERPRINT + }; + private static final int INDEX_KEY_ID = 1; + private static final int INDEX_RANK = 2; + private static final int INDEX_HAS_SECRET = 3; + private static final int INDEX_FINGERPRINT = 4; + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new CursorLoader(getActivity(), Keys.buildKeysUri(mMasterKeyId), + PROJECTION, null, null, null); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + if (!data.moveToFirst()) { + // wut? + return; + } + + boolean allBound = true; + boolean noneBound = true; + + do { + SecretKeyType keyType = SecretKeyType.fromNum(data.getInt(INDEX_HAS_SECRET)); + byte[] fingerprint = data.getBlob(INDEX_FINGERPRINT); + Integer index = naiveIndexOf(mFingerprints, fingerprint); + if (index == null) { + continue; + } + if (keyType == SecretKeyType.DIVERT_TO_CARD) { + noneBound = false; + } else { + allBound = false; + } + } while (data.moveToNext()); + + if (allBound) { + vButton.setVisibility(View.GONE); + vStatus.setText("Key matches, fully bound"); + } else { + vButton.setVisibility(View.VISIBLE); + if (noneBound) { + vStatus.setText("Key matches, can be bound"); + } else { + vStatus.setText("Key matches, partly bound"); + } + } + + } + + public Integer naiveIndexOf(byte[][] haystack, byte[] needle) { + for (int i = 0; i < haystack.length; i++) { + if (Arrays.equals(needle, haystack[i])) { + return i; + } + } + return null; + } + + @Override + public void onLoaderReset(Loader loader) { + + } } diff --git a/OpenKeychain/src/main/res/layout/view_key_yubikey.xml b/OpenKeychain/src/main/res/layout/view_key_yubikey.xml index 7da1fc5c4..83272ef4e 100644 --- a/OpenKeychain/src/main/res/layout/view_key_yubikey.xml +++ b/OpenKeychain/src/main/res/layout/view_key_yubikey.xml @@ -21,7 +21,8 @@ card_view:cardBackgroundColor="@android:color/white" card_view:cardElevation="2dp" card_view:cardUseCompatPadding="true" - card_view:cardCornerRadius="4dp"> + card_view:cardCornerRadius="4dp" + android:animateLayoutChanges="true">