mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-23 17:22:16 -05:00
finish ui flow for yubikey import
This commit is contained in:
parent
2151411219
commit
212bba1869
@ -230,7 +230,7 @@ public class ImportExportOperation extends BaseOperation {
|
|||||||
}
|
}
|
||||||
} catch (Keyserver.QueryFailedException e) {
|
} catch (Keyserver.QueryFailedException e) {
|
||||||
Log.e(Constants.TAG, "query failed", e);
|
Log.e(Constants.TAG, "query failed", e);
|
||||||
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER_ERROR, 3);
|
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER_ERROR, 3, e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.support.v4.app.FragmentTransaction;
|
import android.support.v4.app.FragmentTransaction;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
@ -29,9 +30,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
|||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
|
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
|
||||||
import org.sufficientlysecure.keychain.util.Passphrase;
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -45,6 +43,10 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
|||||||
public static final String EXTRA_ADDITIONAL_EMAILS = "additional_emails";
|
public static final String EXTRA_ADDITIONAL_EMAILS = "additional_emails";
|
||||||
public static final String EXTRA_PASSPHRASE = "passphrase";
|
public static final String EXTRA_PASSPHRASE = "passphrase";
|
||||||
|
|
||||||
|
public static final String EXTRA_NFC_USER_ID = "nfc_user_id";
|
||||||
|
public static final String EXTRA_NFC_AID = "nfc_aid";
|
||||||
|
public static final String EXTRA_NFC_FINGERPRINTS = "nfc_fingerprints";
|
||||||
|
|
||||||
public static final String FRAGMENT_TAG = "currentFragment";
|
public static final String FRAGMENT_TAG = "currentFragment";
|
||||||
|
|
||||||
String mName;
|
String mName;
|
||||||
@ -70,14 +72,29 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
|||||||
|
|
||||||
mCurrentFragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
mCurrentFragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
||||||
} else {
|
} else {
|
||||||
// Initialize members with default values for a new instance
|
|
||||||
mName = getIntent().getStringExtra(EXTRA_NAME);
|
|
||||||
mEmail = getIntent().getStringExtra(EXTRA_EMAIL);
|
|
||||||
mFirstTime = getIntent().getBooleanExtra(EXTRA_FIRST_TIME, false);
|
|
||||||
|
|
||||||
// Start with first fragment of wizard
|
Intent intent = getIntent();
|
||||||
CreateKeyStartFragment frag = CreateKeyStartFragment.newInstance();
|
// Initialize members with default values for a new instance
|
||||||
loadFragment(frag, FragAction.START);
|
mName = intent.getStringExtra(EXTRA_NAME);
|
||||||
|
mEmail = intent.getStringExtra(EXTRA_EMAIL);
|
||||||
|
mFirstTime = intent.getBooleanExtra(EXTRA_FIRST_TIME, false);
|
||||||
|
|
||||||
|
if (intent.hasExtra(EXTRA_NFC_FINGERPRINTS)) {
|
||||||
|
byte[] nfcFingerprints = intent.getByteArrayExtra(EXTRA_NFC_FINGERPRINTS);
|
||||||
|
String nfcUserId = intent.getStringExtra(EXTRA_NFC_USER_ID);
|
||||||
|
byte[] nfcAid = intent.getByteArrayExtra(EXTRA_NFC_AID);
|
||||||
|
|
||||||
|
Fragment frag2 = CreateKeyYubiImportFragment.createInstance(
|
||||||
|
nfcFingerprints, nfcAid, nfcUserId);
|
||||||
|
loadFragment(frag2, FragAction.START);
|
||||||
|
|
||||||
|
setTitle(R.string.title_import_keys);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
CreateKeyStartFragment frag = CreateKeyStartFragment.newInstance();
|
||||||
|
loadFragment(frag, FragAction.START);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mFirstTime) {
|
if (mFirstTime) {
|
||||||
@ -97,15 +114,14 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
byte[] scannedFingerprints = nfcGetFingerprints();
|
byte[] scannedFingerprints = nfcGetFingerprints();
|
||||||
|
byte[] nfcAid = nfcGetAid();
|
||||||
|
String userId = nfcGetUserId();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(scannedFingerprints);
|
long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(scannedFingerprints);
|
||||||
CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId);
|
CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId);
|
||||||
ring.getMasterKeyId();
|
ring.getMasterKeyId();
|
||||||
|
|
||||||
String userId = nfcGetUserId();
|
|
||||||
byte[] nfcAid = nfcGetAid();
|
|
||||||
|
|
||||||
Intent intent = new Intent(this, ViewKeyActivity.class);
|
Intent intent = new Intent(this, ViewKeyActivity.class);
|
||||||
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
|
intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId));
|
||||||
intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid);
|
intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid);
|
||||||
@ -115,7 +131,8 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
|||||||
finish();
|
finish();
|
||||||
|
|
||||||
} catch (PgpKeyNotFoundException e) {
|
} catch (PgpKeyNotFoundException e) {
|
||||||
Fragment frag = CreateKeyYubiFragment.createInstance(scannedFingerprints);
|
Fragment frag = CreateKeyYubiImportFragment.createInstance(
|
||||||
|
scannedFingerprints, nfcAid, userId);
|
||||||
loadFragment(frag, FragAction.TO_RIGHT);
|
loadFragment(frag, FragAction.TO_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,8 +184,10 @@ public class CreateKeyActivity extends BaseNfcActivity {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// do it immediately!
|
// do it immediately!
|
||||||
getSupportFragmentManager().executePendingTransactions();
|
getSupportFragmentManager().executePendingTransactions();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NfcListenerFragment {
|
interface NfcListenerFragment {
|
||||||
|
@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
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;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
|
||||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
|
||||||
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
|
||||||
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
|
||||||
import org.sufficientlysecure.keychain.util.Preferences;
|
|
||||||
|
|
||||||
public class CreateKeyYubiFragment extends Fragment {
|
|
||||||
|
|
||||||
private static final String ARG_FINGERPRINT = "fingerprint";
|
|
||||||
|
|
||||||
CreateKeyActivity mCreateKeyActivity;
|
|
||||||
|
|
||||||
private byte[] mScannedFingerprint;
|
|
||||||
private long mScannedMasterKeyId;
|
|
||||||
|
|
||||||
private TextView mUnknownFingerprint;
|
|
||||||
|
|
||||||
public static Fragment createInstance(byte[] scannedFingerprint) {
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putByteArray(ARG_FINGERPRINT, scannedFingerprint);
|
|
||||||
|
|
||||||
CreateKeyYubiFragment frag = new CreateKeyYubiFragment();
|
|
||||||
frag.setArguments(args);
|
|
||||||
|
|
||||||
return frag;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
mScannedFingerprint = getArguments().getByteArray(ARG_FINGERPRINT);
|
|
||||||
mScannedMasterKeyId = getKeyIdFromFingerprint(mScannedFingerprint);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
View view = inflater.inflate(R.layout.create_yubikey_fragment, container, false);
|
|
||||||
|
|
||||||
mUnknownFingerprint = (TextView) view.findViewById(R.id.create_yubikey_unknown_fp);
|
|
||||||
|
|
||||||
View mBackButton = view.findViewById(R.id.create_key_back_button);
|
|
||||||
View mNextButton = view.findViewById(R.id.create_key_next_button);
|
|
||||||
|
|
||||||
mBackButton.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mNextButton.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
nextClicked();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Activity activity) {
|
|
||||||
super.onAttach(activity);
|
|
||||||
mCreateKeyActivity = (CreateKeyActivity) getActivity();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void nextClicked() {
|
|
||||||
importKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void importKey() {
|
|
||||||
|
|
||||||
// Message is received after decrypting is done in KeychainIntentService
|
|
||||||
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity()) {
|
|
||||||
public void handleMessage(Message message) {
|
|
||||||
// handle messages by standard KeychainIntentServiceHandler first
|
|
||||||
super.handleMessage(message);
|
|
||||||
|
|
||||||
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
|
||||||
// get returned data bundle
|
|
||||||
Bundle returnData = message.getData();
|
|
||||||
|
|
||||||
ImportKeyResult result =
|
|
||||||
returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT);
|
|
||||||
|
|
||||||
result.createNotify(getActivity()).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send all information needed to service to decrypt in other thread
|
|
||||||
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
|
|
||||||
|
|
||||||
// fill values for this action
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
|
|
||||||
intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING);
|
|
||||||
|
|
||||||
String hexFp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint);
|
|
||||||
ArrayList<ParcelableKeyRing> keyList = new ArrayList<>();
|
|
||||||
keyList.add(new ParcelableKeyRing(hexFp, null, null));
|
|
||||||
data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, keyList);
|
|
||||||
|
|
||||||
{
|
|
||||||
Preferences prefs = Preferences.getPreferences(getActivity());
|
|
||||||
Preferences.CloudSearchPrefs cloudPrefs =
|
|
||||||
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
|
||||||
data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
|
||||||
Messenger messenger = new Messenger(saveHandler);
|
|
||||||
intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
|
|
||||||
|
|
||||||
// start service with intent
|
|
||||||
getActivity().startService(intent);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static long getKeyIdFromFingerprint(byte[] fingerprint) {
|
|
||||||
ByteBuffer buf = ByteBuffer.wrap(fingerprint);
|
|
||||||
// skip first 12 bytes of the fingerprint
|
|
||||||
buf.position(12);
|
|
||||||
// the last eight bytes are the key id (big endian, which is default order in ByteBuffer)
|
|
||||||
return buf.getLong();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,256 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.os.Messenger;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
|
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||||
|
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
|
||||||
|
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
import org.sufficientlysecure.keychain.util.Preferences;
|
||||||
|
|
||||||
|
|
||||||
|
public class CreateKeyYubiImportFragment extends Fragment implements NfcListenerFragment {
|
||||||
|
|
||||||
|
private static final String ARG_FINGERPRINT = "fingerprint";
|
||||||
|
public static final String ARG_AID = "aid";
|
||||||
|
public static final String ARG_USER_ID = "user_ids";
|
||||||
|
|
||||||
|
CreateKeyActivity mCreateKeyActivity;
|
||||||
|
|
||||||
|
private byte[] mNfcFingerprints;
|
||||||
|
private long mNfcMasterKeyId;
|
||||||
|
private byte[] mNfcAid;
|
||||||
|
private String mNfcUserId;
|
||||||
|
private String mNfcFingerprint;
|
||||||
|
private ImportKeysListFragment mListFragment;
|
||||||
|
private TextView vSerNo;
|
||||||
|
private TextView vUserId;
|
||||||
|
|
||||||
|
public static Fragment createInstance(byte[] scannedFingerprints, byte[] nfcAid, String userId) {
|
||||||
|
|
||||||
|
CreateKeyYubiImportFragment frag = new CreateKeyYubiImportFragment();
|
||||||
|
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putByteArray(ARG_FINGERPRINT, scannedFingerprints);
|
||||||
|
args.putByteArray(ARG_AID, nfcAid);
|
||||||
|
args.putString(ARG_USER_ID, userId);
|
||||||
|
frag.setArguments(args);
|
||||||
|
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
Bundle args = savedInstanceState != null ? savedInstanceState : getArguments();
|
||||||
|
|
||||||
|
mNfcFingerprints = args.getByteArray(ARG_FINGERPRINT);
|
||||||
|
mNfcAid = args.getByteArray(ARG_AID);
|
||||||
|
mNfcUserId = args.getString(ARG_USER_ID);
|
||||||
|
|
||||||
|
mNfcMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints);
|
||||||
|
mNfcFingerprint = KeyFormattingUtils.convertFingerprintToHex(mNfcFingerprints);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.create_yubikey_import_fragment, container, false);
|
||||||
|
|
||||||
|
vSerNo = (TextView) view.findViewById(R.id.yubikey_serno);
|
||||||
|
vUserId = (TextView) view.findViewById(R.id.yubikey_userid);
|
||||||
|
|
||||||
|
{
|
||||||
|
View mBackButton = view.findViewById(R.id.create_key_back_button);
|
||||||
|
mBackButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (getFragmentManager().getBackStackEntryCount() == 0) {
|
||||||
|
getActivity().setResult(Activity.RESULT_CANCELED);
|
||||||
|
getActivity().finish();
|
||||||
|
} else {
|
||||||
|
mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
View mNextButton = view.findViewById(R.id.create_key_next_button);
|
||||||
|
mNextButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
importKey();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mListFragment = ImportKeysListFragment.newInstance(null, null, "0x" + mNfcFingerprint, true);
|
||||||
|
|
||||||
|
view.findViewById(R.id.button_search).setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
refreshSearch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setData();
|
||||||
|
|
||||||
|
getFragmentManager().beginTransaction()
|
||||||
|
.replace(R.id.yubikey_import_fragment, mListFragment, "yubikey_import")
|
||||||
|
.commit();
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle args) {
|
||||||
|
super.onSaveInstanceState(args);
|
||||||
|
|
||||||
|
args.putByteArray(ARG_FINGERPRINT, mNfcFingerprints);
|
||||||
|
args.putByteArray(ARG_AID, mNfcAid);
|
||||||
|
args.putString(ARG_USER_ID, mNfcUserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
mCreateKeyActivity = (CreateKeyActivity) getActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData() {
|
||||||
|
String serno = Hex.toHexString(mNfcAid, 10, 4);
|
||||||
|
vSerNo.setText(getString(R.string.yubikey_serno, serno));
|
||||||
|
|
||||||
|
if (!mNfcUserId.isEmpty()) {
|
||||||
|
vUserId.setText(getString(R.string.yubikey_key_holder, mNfcUserId));
|
||||||
|
} else {
|
||||||
|
vUserId.setText(getString(R.string.yubikey_key_holder_unset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshSearch() {
|
||||||
|
mListFragment.loadNew(new ImportKeysListFragment.CloudLoaderState("0x" + mNfcFingerprint,
|
||||||
|
Preferences.getPreferences(getActivity()).getCloudSearchPrefs()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void importKey() {
|
||||||
|
|
||||||
|
// Message is received after decrypting is done in KeychainIntentService
|
||||||
|
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
|
||||||
|
getString(R.string.progress_importing), ProgressDialog.STYLE_HORIZONTAL) {
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
// handle messages by standard KeychainIntentServiceHandler first
|
||||||
|
super.handleMessage(message);
|
||||||
|
|
||||||
|
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
|
||||||
|
// get returned data bundle
|
||||||
|
Bundle returnData = message.getData();
|
||||||
|
|
||||||
|
ImportKeyResult result =
|
||||||
|
returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT);
|
||||||
|
|
||||||
|
if (!result.success()) {
|
||||||
|
result.createNotify(getActivity()).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent intent = new Intent(getActivity(), ViewKeyActivity.class);
|
||||||
|
intent.setData(KeyRings.buildGenericKeyRingUri(mNfcMasterKeyId));
|
||||||
|
intent.putExtra(ViewKeyActivity.EXTRA_DISPLAY_RESULT, result);
|
||||||
|
intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid);
|
||||||
|
intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId);
|
||||||
|
intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints);
|
||||||
|
startActivity(intent);
|
||||||
|
getActivity().finish();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send all information needed to service to decrypt in other thread
|
||||||
|
Intent intent = new Intent(getActivity(), KeychainIntentService.class);
|
||||||
|
|
||||||
|
// fill values for this action
|
||||||
|
Bundle data = new Bundle();
|
||||||
|
|
||||||
|
intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING);
|
||||||
|
|
||||||
|
String hexFp = KeyFormattingUtils.convertFingerprintToHex(mNfcFingerprints);
|
||||||
|
ArrayList<ParcelableKeyRing> keyList = new ArrayList<>();
|
||||||
|
keyList.add(new ParcelableKeyRing(hexFp, null, null));
|
||||||
|
data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, keyList);
|
||||||
|
|
||||||
|
{
|
||||||
|
Preferences prefs = Preferences.getPreferences(getActivity());
|
||||||
|
Preferences.CloudSearchPrefs cloudPrefs =
|
||||||
|
new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
|
||||||
|
data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||||
|
|
||||||
|
// Create a new Messenger for the communication back
|
||||||
|
Messenger messenger = new Messenger(saveHandler);
|
||||||
|
intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
|
||||||
|
|
||||||
|
saveHandler.showProgressDialog(getActivity());
|
||||||
|
|
||||||
|
// start service with intent
|
||||||
|
getActivity().startService(intent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNfcPerform() throws IOException {
|
||||||
|
|
||||||
|
mNfcFingerprints = mCreateKeyActivity.nfcGetFingerprints();
|
||||||
|
mNfcAid = mCreateKeyActivity.nfcGetAid();
|
||||||
|
mNfcUserId = mCreateKeyActivity.nfcGetUserId();
|
||||||
|
|
||||||
|
mNfcMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints);
|
||||||
|
mNfcFingerprint = KeyFormattingUtils.convertFingerprintToHex(mNfcFingerprints);
|
||||||
|
|
||||||
|
setData();
|
||||||
|
refreshSearch();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -53,9 +53,11 @@ import java.util.List;
|
|||||||
|
|
||||||
public class ImportKeysListFragment extends ListFragment implements
|
public class ImportKeysListFragment extends ListFragment implements
|
||||||
LoaderManager.LoaderCallbacks<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
|
LoaderManager.LoaderCallbacks<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
|
||||||
|
|
||||||
private static final String ARG_DATA_URI = "uri";
|
private static final String ARG_DATA_URI = "uri";
|
||||||
private static final String ARG_BYTES = "bytes";
|
private static final String ARG_BYTES = "bytes";
|
||||||
private static final String ARG_SERVER_QUERY = "query";
|
public static final String ARG_SERVER_QUERY = "query";
|
||||||
|
public static final String ARG_NON_INTERACTIVE = "non_interactive";
|
||||||
|
|
||||||
private Activity mActivity;
|
private Activity mActivity;
|
||||||
private ImportKeysAdapter mAdapter;
|
private ImportKeysAdapter mAdapter;
|
||||||
@ -66,6 +68,7 @@ public class ImportKeysListFragment extends ListFragment implements
|
|||||||
private static final int LOADER_ID_CLOUD = 1;
|
private static final int LOADER_ID_CLOUD = 1;
|
||||||
|
|
||||||
private LongSparseArray<ParcelableKeyRing> mCachedKeyData;
|
private LongSparseArray<ParcelableKeyRing> mCachedKeyData;
|
||||||
|
private boolean mNonInteractive;
|
||||||
|
|
||||||
public LoaderState getLoaderState() {
|
public LoaderState getLoaderState() {
|
||||||
return mLoaderState;
|
return mLoaderState;
|
||||||
@ -118,16 +121,19 @@ public class ImportKeysListFragment extends ListFragment implements
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates new instance of this fragment
|
|
||||||
*/
|
|
||||||
public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, String serverQuery) {
|
public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, String serverQuery) {
|
||||||
|
return newInstance(bytes, dataUri, serverQuery, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri,
|
||||||
|
String serverQuery, boolean nonInteractive) {
|
||||||
ImportKeysListFragment frag = new ImportKeysListFragment();
|
ImportKeysListFragment frag = new ImportKeysListFragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putByteArray(ARG_BYTES, bytes);
|
args.putByteArray(ARG_BYTES, bytes);
|
||||||
args.putParcelable(ARG_DATA_URI, dataUri);
|
args.putParcelable(ARG_DATA_URI, dataUri);
|
||||||
args.putString(ARG_SERVER_QUERY, serverQuery);
|
args.putString(ARG_SERVER_QUERY, serverQuery);
|
||||||
|
args.putBoolean(ARG_NON_INTERACTIVE, nonInteractive);
|
||||||
|
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
@ -173,9 +179,11 @@ public class ImportKeysListFragment extends ListFragment implements
|
|||||||
mAdapter = new ImportKeysAdapter(mActivity);
|
mAdapter = new ImportKeysAdapter(mActivity);
|
||||||
setListAdapter(mAdapter);
|
setListAdapter(mAdapter);
|
||||||
|
|
||||||
Uri dataUri = getArguments().getParcelable(ARG_DATA_URI);
|
Bundle args = getArguments();
|
||||||
byte[] bytes = getArguments().getByteArray(ARG_BYTES);
|
Uri dataUri = args.containsKey(ARG_DATA_URI) ? args.<Uri>getParcelable(ARG_DATA_URI) : null;
|
||||||
String query = getArguments().getString(ARG_SERVER_QUERY);
|
byte[] bytes = args.containsKey(ARG_BYTES) ? args.getByteArray(ARG_BYTES) : null;
|
||||||
|
String query = args.containsKey(ARG_SERVER_QUERY) ? args.getString(ARG_SERVER_QUERY) : null;
|
||||||
|
mNonInteractive = args.containsKey(ARG_NON_INTERACTIVE) ? args.getBoolean(ARG_NON_INTERACTIVE) : false;
|
||||||
|
|
||||||
if (dataUri != null || bytes != null) {
|
if (dataUri != null || bytes != null) {
|
||||||
mLoaderState = new BytesLoaderState(bytes, dataUri);
|
mLoaderState = new BytesLoaderState(bytes, dataUri);
|
||||||
@ -203,6 +211,10 @@ public class ImportKeysListFragment extends ListFragment implements
|
|||||||
public void onListItemClick(ListView l, View v, int position, long id) {
|
public void onListItemClick(ListView l, View v, int position, long id) {
|
||||||
super.onListItemClick(l, v, position, id);
|
super.onListItemClick(l, v, position, id);
|
||||||
|
|
||||||
|
if (mNonInteractive) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Select checkbox!
|
// Select checkbox!
|
||||||
// Update underlying data and notify adapter of change. The adapter will
|
// Update underlying data and notify adapter of change. The adapter will
|
||||||
// update the view automatically.
|
// update the view automatically.
|
||||||
|
@ -98,6 +98,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
|||||||
static final int REQUEST_QR_FINGERPRINT = 1;
|
static final int REQUEST_QR_FINGERPRINT = 1;
|
||||||
static final int REQUEST_DELETE = 2;
|
static final int REQUEST_DELETE = 2;
|
||||||
static final int REQUEST_EXPORT = 3;
|
static final int REQUEST_EXPORT = 3;
|
||||||
|
public static final String EXTRA_DISPLAY_RESULT = "display_result";
|
||||||
|
|
||||||
ExportHelper mExportHelper;
|
ExportHelper mExportHelper;
|
||||||
ProviderHelper mProviderHelper;
|
ProviderHelper mProviderHelper;
|
||||||
@ -268,6 +269,11 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
|||||||
mNfcHelper = new NfcHelper(this, mProviderHelper);
|
mNfcHelper = new NfcHelper(this, mProviderHelper);
|
||||||
mNfcHelper.initNfc(mDataUri);
|
mNfcHelper.initNfc(mDataUri);
|
||||||
|
|
||||||
|
if (savedInstanceState == null && getIntent().hasExtra(EXTRA_DISPLAY_RESULT)) {
|
||||||
|
OperationResult result = getIntent().getParcelableExtra(EXTRA_DISPLAY_RESULT);
|
||||||
|
result.createNotify(this).show();
|
||||||
|
}
|
||||||
|
|
||||||
startFragment(savedInstanceState, mDataUri);
|
startFragment(savedInstanceState, mDataUri);
|
||||||
|
|
||||||
if (savedInstanceState == null && getIntent().hasExtra(EXTRA_NFC_AID)) {
|
if (savedInstanceState == null && getIntent().hasExtra(EXTRA_NFC_AID)) {
|
||||||
@ -570,7 +576,19 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
} catch (PgpKeyNotFoundException e) {
|
} catch (PgpKeyNotFoundException e) {
|
||||||
Notify.create(this, "Different key stored on Yubikey!", Style.ERROR).show();
|
Notify.create(this, "Different key stored on Yubikey!", Notify.LENGTH_LONG,
|
||||||
|
Style.WARN, new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void onAction() {
|
||||||
|
Intent intent = new Intent(
|
||||||
|
ViewKeyActivity.this, CreateKeyActivity.class);
|
||||||
|
intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid);
|
||||||
|
intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId);
|
||||||
|
intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints);
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}, R.string.snack_yubikey_import).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,11 +196,9 @@ public class ViewKeyYubikeyFragment extends Fragment
|
|||||||
vStatus.setText(R.string.yubikey_status_bound);
|
vStatus.setText(R.string.yubikey_status_bound);
|
||||||
} else {
|
} else {
|
||||||
vButton.setVisibility(View.VISIBLE);
|
vButton.setVisibility(View.VISIBLE);
|
||||||
if (noneBound) {
|
vStatus.setText(noneBound
|
||||||
vStatus.setText(R.string.yubikey_status_unbound);
|
? R.string.yubikey_status_unbound
|
||||||
} else {
|
: R.string.yubikey_status_partly);
|
||||||
vStatus.setText(R.string.yubikey_status_partly);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,38 +3,79 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ScrollView
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:fillViewport="true"
|
android:padding="4dp"
|
||||||
android:layout_above="@+id/create_key_buttons">
|
android:orientation="horizontal"
|
||||||
|
android:id="@+id/yubikey_status_layout" >
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_margin="14dp"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:src="@drawable/yubi_icon"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/yubikey_serno"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginLeft="8dp"
|
android:text="Yubikey #"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
/>
|
||||||
android:id="@+id/create_yubikey_unknown_fp"
|
|
||||||
android:text="(yubikey fingerprint)" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/yubikey_userid"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginLeft="8dp"
|
android:text="User ID"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
/>
|
||||||
android:text="Hit next to import this key"
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/yubikey_status"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:text="Unknown key, hit next to import"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
<ImageButton
|
||||||
|
android:id="@+id/button_search"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_search_grey_24dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:background="?android:selectableItemBackground" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_height="1dip"
|
||||||
|
android:layout_below="@id/yubikey_status_layout"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/yubikey_import_fragment"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/yubikey_status_layout"
|
||||||
|
android:layout_above="@id/create_key_buttons"
|
||||||
|
/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -71,10 +112,10 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="@string/btn_next"
|
android:text="@string/btn_import"
|
||||||
android:textAllCaps="true"
|
android:textAllCaps="true"
|
||||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
android:drawableRight="@drawable/ic_chevron_right_grey_24dp"
|
android:drawableRight="@drawable/ic_key_plus_grey600_24dp"
|
||||||
android:drawablePadding="8dp"
|
android:drawablePadding="8dp"
|
||||||
android:gravity="right|center_vertical"
|
android:gravity="right|center_vertical"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
@ -1124,7 +1124,7 @@
|
|||||||
<string name="msg_import_fetch_error_decode">"Error decoding retrieved keyring!"</string>
|
<string name="msg_import_fetch_error_decode">"Error decoding retrieved keyring!"</string>
|
||||||
<string name="msg_import_fetch_error">"Key could not be retrieved! (Network problems?)"</string>
|
<string name="msg_import_fetch_error">"Key could not be retrieved! (Network problems?)"</string>
|
||||||
<string name="msg_import_fetch_keybase">"Retrieving from keybase.io: %s"</string>
|
<string name="msg_import_fetch_keybase">"Retrieving from keybase.io: %s"</string>
|
||||||
<string name="msg_import_fetch_keyserver_error">"Could not retrieve key from keybase!"</string>
|
<string name="msg_import_fetch_keyserver_error">"Could not retrieve key from keyservers: %s"</string>
|
||||||
<string name="msg_import_fetch_keyserver">"Retrieving from keyserver: %s"</string>
|
<string name="msg_import_fetch_keyserver">"Retrieving from keyserver: %s"</string>
|
||||||
<string name="msg_import_fetch_keyserver_ok">"Key retrieval successful"</string>
|
<string name="msg_import_fetch_keyserver_ok">"Key retrieval successful"</string>
|
||||||
<string name="msg_import_keyserver">"Using keyserver %s"</string>
|
<string name="msg_import_keyserver">"Using keyserver %s"</string>
|
||||||
@ -1267,13 +1267,15 @@
|
|||||||
<string name="nfc_write_succesful">Successfully written on NFC tag</string>
|
<string name="nfc_write_succesful">Successfully written on NFC tag</string>
|
||||||
<string name="unlocked">Unlocked</string>
|
<string name="unlocked">Unlocked</string>
|
||||||
<string name="nfc_settings">Settings</string>
|
<string name="nfc_settings">Settings</string>
|
||||||
<string name="snack_yubikey_view">View</string>
|
<string name="snack_yubikey_view">"View"</string>
|
||||||
<string name="button_bind_key">Bind Key</string>
|
<string name="snack_yubikey_import">"Import"</string>
|
||||||
|
<string name="button_bind_key">"Bind Key"</string>
|
||||||
<string name="yubikey_serno">"Serial No: %s"</string>
|
<string name="yubikey_serno">"Serial No: %s"</string>
|
||||||
<string name="yubikey_key_holder">"Key holder: "</string>
|
<string name="yubikey_key_holder">"Key holder: "</string>
|
||||||
<string name="yubikey_key_holder_unset">"Key holder: <unset>"</string>
|
<string name="yubikey_key_holder_unset">"Key holder: <unset>"</string>
|
||||||
<string name="yubikey_status_bound">Yubikey matches, bound to key</string>
|
<string name="yubikey_status_bound">"Yubikey matches, bound to key"</string>
|
||||||
<string name="yubikey_status_unbound">Yubikey matches, can be bound to key</string>
|
<string name="yubikey_status_unbound">"Yubikey matches, can be bound to key"</string>
|
||||||
<string name="yubikey_status_partly">Yubikey matches, partly bound to key</string>
|
<string name="yubikey_status_partly">"Yubikey matches, partly bound to key"</string>
|
||||||
|
<string name="btn_import">"Import"</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user