token-import: load from file
This commit is contained in:
@@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
@@ -48,6 +49,7 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
|||||||
import org.sufficientlysecure.keychain.ui.widget.StatusIndicator;
|
import org.sufficientlysecure.keychain.ui.widget.StatusIndicator;
|
||||||
import org.sufficientlysecure.keychain.ui.widget.StatusIndicator.Status;
|
import org.sufficientlysecure.keychain.ui.widget.StatusIndicator.Status;
|
||||||
import org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator;
|
import org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator;
|
||||||
|
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||||
|
|
||||||
|
|
||||||
public class CreateSecurityTokenImportFragment extends Fragment implements CreateSecurityTokenImportMvpView,
|
public class CreateSecurityTokenImportFragment extends Fragment implements CreateSecurityTokenImportMvpView,
|
||||||
@@ -56,6 +58,7 @@ public class CreateSecurityTokenImportFragment extends Fragment implements Creat
|
|||||||
private static final String ARG_AID = "aid";
|
private static final String ARG_AID = "aid";
|
||||||
private static final String ARG_USER_ID = "user_ids";
|
private static final String ARG_USER_ID = "user_ids";
|
||||||
private static final String ARG_URL = "key_uri";
|
private static final String ARG_URL = "key_uri";
|
||||||
|
public static final int REQUEST_CODE_OPEN_FILE = 0;
|
||||||
|
|
||||||
CreateSecurityTokenImportPresenter presenter;
|
CreateSecurityTokenImportPresenter presenter;
|
||||||
private ViewGroup statusLayoutGroup;
|
private ViewGroup statusLayoutGroup;
|
||||||
@@ -114,6 +117,7 @@ public class CreateSecurityTokenImportFragment extends Fragment implements Creat
|
|||||||
view.findViewById(R.id.button_reset_token_1).setOnClickListener(this);
|
view.findViewById(R.id.button_reset_token_1).setOnClickListener(this);
|
||||||
view.findViewById(R.id.button_reset_token_2).setOnClickListener(this);
|
view.findViewById(R.id.button_reset_token_2).setOnClickListener(this);
|
||||||
view.findViewById(R.id.button_reset_token_3).setOnClickListener(this);
|
view.findViewById(R.id.button_reset_token_3).setOnClickListener(this);
|
||||||
|
view.findViewById(R.id.button_load_file).setOnClickListener(this);
|
||||||
|
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
@@ -228,6 +232,27 @@ public class CreateSecurityTokenImportFragment extends Fragment implements Creat
|
|||||||
cryptoPromoteOperationHelper.cryptoOperation();
|
cryptoPromoteOperationHelper.cryptoOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showFileSelectDialog() {
|
||||||
|
FileHelper.openDocument(this, null, "*/*", false, REQUEST_CODE_OPEN_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
switch (requestCode) {
|
||||||
|
case REQUEST_CODE_OPEN_FILE: {
|
||||||
|
if (resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {
|
||||||
|
Uri fileUri = data.getData();
|
||||||
|
presenter.onFileSelected(fileUri);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
switch (v.getId()) {
|
switch (v.getId()) {
|
||||||
@@ -243,6 +268,9 @@ public class CreateSecurityTokenImportFragment extends Fragment implements Creat
|
|||||||
presenter.onClickViewKey();
|
presenter.onClickViewKey();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case R.id.button_load_file: {
|
||||||
|
presenter.onClickLoadFile();
|
||||||
|
}
|
||||||
case R.id.button_reset_token_1:
|
case R.id.button_reset_token_1:
|
||||||
case R.id.button_reset_token_2:
|
case R.id.button_reset_token_2:
|
||||||
case R.id.button_reset_token_3: {
|
case R.id.button_reset_token_3: {
|
||||||
@@ -298,7 +326,8 @@ public class CreateSecurityTokenImportFragment extends Fragment implements Creat
|
|||||||
SEARCH_KEYSERVER (R.string.status_search_keyserver),
|
SEARCH_KEYSERVER (R.string.status_search_keyserver),
|
||||||
IMPORT (R.string.status_import),
|
IMPORT (R.string.status_import),
|
||||||
TOKEN_PROMOTE(R.string.status_token_promote),
|
TOKEN_PROMOTE(R.string.status_token_promote),
|
||||||
TOKEN_CHECK (R.string.status_token_check);
|
TOKEN_CHECK (R.string.status_token_check),
|
||||||
|
SEARCH_CONTENT_URI (R.string.status_content_uri);
|
||||||
|
|
||||||
@StringRes
|
@StringRes
|
||||||
private int stringRes;
|
private int stringRes;
|
||||||
|
|||||||
@@ -19,13 +19,14 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeyRepository;
|
|
||||||
import org.sufficientlysecure.keychain.ui.CreateSecurityTokenImportFragment.StatusLine;
|
import org.sufficientlysecure.keychain.ui.CreateSecurityTokenImportFragment.StatusLine;
|
||||||
|
import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.ContentUriRetrievalLoader;
|
||||||
import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.KeyRetrievalResult;
|
import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.KeyRetrievalResult;
|
||||||
import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.KeyserverRetrievalLoader;
|
import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.KeyserverRetrievalLoader;
|
||||||
import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.LocalKeyLookupLoader;
|
import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.LocalKeyLookupLoader;
|
||||||
@@ -36,6 +37,8 @@ class CreateSecurityTokenImportPresenter {
|
|||||||
private static final int LOADER_LOCAL = 0;
|
private static final int LOADER_LOCAL = 0;
|
||||||
private static final int LOADER_URI = 1;
|
private static final int LOADER_URI = 1;
|
||||||
private static final int LOADER_KEYSERVER = 2;
|
private static final int LOADER_KEYSERVER = 2;
|
||||||
|
private static final int LOADER_CONTENT_URI = 3;
|
||||||
|
private static final String ARG_CONTENT_URI = "content_uri";
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
|
|
||||||
@@ -119,6 +122,9 @@ class CreateSecurityTokenImportPresenter {
|
|||||||
return new UriKeyRetrievalLoader(context, tokenUrl, tokenFingerprints);
|
return new UriKeyRetrievalLoader(context, tokenUrl, tokenFingerprints);
|
||||||
case LOADER_KEYSERVER:
|
case LOADER_KEYSERVER:
|
||||||
return new KeyserverRetrievalLoader(context, tokenFingerprints[0]);
|
return new KeyserverRetrievalLoader(context, tokenFingerprints[0]);
|
||||||
|
case LOADER_CONTENT_URI:
|
||||||
|
return new ContentUriRetrievalLoader(context, tokenFingerprints[0],
|
||||||
|
args.<Uri>getParcelable(ARG_CONTENT_URI));
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("called with unknown loader id!");
|
throw new IllegalArgumentException("called with unknown loader id!");
|
||||||
}
|
}
|
||||||
@@ -138,6 +144,10 @@ class CreateSecurityTokenImportPresenter {
|
|||||||
searchedKeyservers = true;
|
searchedKeyservers = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LOADER_CONTENT_URI: {
|
||||||
|
// nothing to do here
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
throw new IllegalArgumentException("called with unknown loader id!");
|
throw new IllegalArgumentException("called with unknown loader id!");
|
||||||
}
|
}
|
||||||
@@ -218,7 +228,20 @@ class CreateSecurityTokenImportPresenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onClickResetToken() {
|
public void onClickResetToken() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void onClickLoadFile() {
|
||||||
|
view.showFileSelectDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onFileSelected(Uri contentUri) {
|
||||||
|
view.resetStatusLines();
|
||||||
|
view.statusLineAdd(StatusLine.SEARCH_CONTENT_URI);
|
||||||
|
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putParcelable(ARG_CONTENT_URI, contentUri);
|
||||||
|
loaderManager.restartLoader(LOADER_CONTENT_URI, args, loaderCallbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreateSecurityTokenImportMvpView {
|
interface CreateSecurityTokenImportMvpView {
|
||||||
@@ -236,5 +259,7 @@ class CreateSecurityTokenImportPresenter {
|
|||||||
void operationPromote(long masterKeyId, byte[] cardAid);
|
void operationPromote(long masterKeyId, byte[] cardAid);
|
||||||
|
|
||||||
void finishAndShowKey(long masterKeyId);
|
void finishAndShowKey(long masterKeyId);
|
||||||
|
|
||||||
|
void showFileSelectDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,16 +18,21 @@
|
|||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.content.AsyncTaskLoader;
|
import android.support.v4.content.AsyncTaskLoader;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.auto.value.AutoValue;
|
import com.google.auto.value.AutoValue;
|
||||||
|
import okhttp3.Call;
|
||||||
import okhttp3.Request.Builder;
|
import okhttp3.Request.Builder;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
@@ -35,10 +40,9 @@ import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
|
|||||||
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverClient;
|
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverClient;
|
||||||
import org.sufficientlysecure.keychain.keyimport.KeyserverClient.QueryFailedException;
|
import org.sufficientlysecure.keychain.keyimport.KeyserverClient.QueryFailedException;
|
||||||
import org.sufficientlysecure.keychain.network.OkHttpClientFactory;
|
import org.sufficientlysecure.keychain.network.OkHttpClientFactory;
|
||||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
|
||||||
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
||||||
import org.sufficientlysecure.keychain.provider.KeyRepository;
|
import org.sufficientlysecure.keychain.provider.KeyRepository;
|
||||||
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
|
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
|
||||||
@@ -66,7 +70,7 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
|
|||||||
KeyRetrievalResult keyRetrievalResult = super.onLoadInBackground();
|
KeyRetrievalResult keyRetrievalResult = super.onLoadInBackground();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
long elapsedTime = startTime - SystemClock.elapsedRealtime();
|
long elapsedTime = SystemClock.elapsedRealtime() - startTime;
|
||||||
if (elapsedTime < MIN_OPERATION_TIME_MILLIS) {
|
if (elapsedTime < MIN_OPERATION_TIME_MILLIS) {
|
||||||
Thread.sleep(MIN_OPERATION_TIME_MILLIS - elapsedTime);
|
Thread.sleep(MIN_OPERATION_TIME_MILLIS - elapsedTime);
|
||||||
}
|
}
|
||||||
@@ -130,8 +134,8 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
|
|||||||
@Override
|
@Override
|
||||||
public KeyRetrievalResult loadInBackground() {
|
public KeyRetrievalResult loadInBackground() {
|
||||||
try {
|
try {
|
||||||
Response execute =
|
Call call = OkHttpClientFactory.getSimpleClient().newCall(new Builder().url(yubikeyUri).build());
|
||||||
OkHttpClientFactory.getSimpleClient().newCall(new Builder().url(yubikeyUri).build()).execute();
|
Response execute = call.execute();
|
||||||
if (execute.isSuccessful()) {
|
if (execute.isSuccessful()) {
|
||||||
UncachedKeyRing keyRing = UncachedKeyRing.decodeFromData(execute.body().bytes());
|
UncachedKeyRing keyRing = UncachedKeyRing.decodeFromData(execute.body().bytes());
|
||||||
if (Arrays.equals(fingerprints[0], keyRing.getFingerprint())) {
|
if (Arrays.equals(fingerprints[0], keyRing.getFingerprint())) {
|
||||||
@@ -162,6 +166,10 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
|
|||||||
|
|
||||||
HkpKeyserverClient keyserverClient = HkpKeyserverClient.fromHkpKeyserverAddress(preferredKeyserver);
|
HkpKeyserverClient keyserverClient = HkpKeyserverClient.fromHkpKeyserverAddress(preferredKeyserver);
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
return KeyRetrievalResult.createWithError();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String keyString =
|
String keyString =
|
||||||
keyserverClient.get("0x" + KeyFormattingUtils.convertFingerprintToHex(fingerprint), parcelableProxy);
|
keyserverClient.get("0x" + KeyFormattingUtils.convertFingerprintToHex(fingerprint), parcelableProxy);
|
||||||
@@ -176,6 +184,43 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ContentUriRetrievalLoader extends PublicKeyRetrievalLoader {
|
||||||
|
private final ContentResolver contentResolver;
|
||||||
|
private final byte[] fingerprint;
|
||||||
|
private final Uri uri;
|
||||||
|
|
||||||
|
public ContentUriRetrievalLoader(Context context, byte[] fingerprint, Uri uri) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
this.fingerprint = fingerprint;
|
||||||
|
this.uri = uri;
|
||||||
|
this.contentResolver = context.getContentResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyRetrievalResult loadInBackground() {
|
||||||
|
try {
|
||||||
|
InputStream is = contentResolver.openInputStream(uri);
|
||||||
|
if (is == null) {
|
||||||
|
return KeyRetrievalResult.createWithError();
|
||||||
|
}
|
||||||
|
|
||||||
|
IteratorWithIOThrow<UncachedKeyRing> uncachedKeyRingIterator = UncachedKeyRing.fromStream(
|
||||||
|
new BufferedInputStream(is));
|
||||||
|
while (uncachedKeyRingIterator.hasNext()) {
|
||||||
|
UncachedKeyRing keyRing = uncachedKeyRingIterator.next();
|
||||||
|
if (Arrays.equals(fingerprint, keyRing.getFingerprint())) {
|
||||||
|
return KeyRetrievalResult.createWithKeyringdata(keyRing.getMasterKeyId(), keyRing.getEncoded());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "error retrieving key from keyserver", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return KeyRetrievalResult.createWithError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deliverResult(KeyRetrievalResult result) {
|
public void deliverResult(KeyRetrievalResult result) {
|
||||||
cachedResult = result;
|
cachedResult = result;
|
||||||
|
|||||||
@@ -1924,5 +1924,6 @@
|
|||||||
<string name="status_import">Importing key…</string>
|
<string name="status_import">Importing key…</string>
|
||||||
<string name="status_token_promote">Setting up key…</string>
|
<string name="status_token_promote">Setting up key…</string>
|
||||||
<string name="status_token_check">Checking key setup…</string>
|
<string name="status_token_check">Checking key setup…</string>
|
||||||
|
<string name="status_content_uri">Reading file…</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user