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.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
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.Status;
|
||||
import org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator;
|
||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
|
||||
|
||||
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_USER_ID = "user_ids";
|
||||
private static final String ARG_URL = "key_uri";
|
||||
public static final int REQUEST_CODE_OPEN_FILE = 0;
|
||||
|
||||
CreateSecurityTokenImportPresenter presenter;
|
||||
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_2).setOnClickListener(this);
|
||||
view.findViewById(R.id.button_reset_token_3).setOnClickListener(this);
|
||||
view.findViewById(R.id.button_load_file).setOnClickListener(this);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
@@ -228,6 +232,27 @@ public class CreateSecurityTokenImportFragment extends Fragment implements Creat
|
||||
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
|
||||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
@@ -243,6 +268,9 @@ public class CreateSecurityTokenImportFragment extends Fragment implements Creat
|
||||
presenter.onClickViewKey();
|
||||
break;
|
||||
}
|
||||
case R.id.button_load_file: {
|
||||
presenter.onClickLoadFile();
|
||||
}
|
||||
case R.id.button_reset_token_1:
|
||||
case R.id.button_reset_token_2:
|
||||
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),
|
||||
IMPORT (R.string.status_import),
|
||||
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
|
||||
private int stringRes;
|
||||
|
||||
@@ -19,13 +19,14 @@ package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
import android.support.v4.content.Loader;
|
||||
|
||||
import org.sufficientlysecure.keychain.provider.KeyRepository;
|
||||
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.KeyserverRetrievalLoader;
|
||||
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_URI = 1;
|
||||
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;
|
||||
|
||||
@@ -119,6 +122,9 @@ class CreateSecurityTokenImportPresenter {
|
||||
return new UriKeyRetrievalLoader(context, tokenUrl, tokenFingerprints);
|
||||
case LOADER_KEYSERVER:
|
||||
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!");
|
||||
}
|
||||
@@ -138,6 +144,10 @@ class CreateSecurityTokenImportPresenter {
|
||||
searchedKeyservers = true;
|
||||
break;
|
||||
}
|
||||
case LOADER_CONTENT_URI: {
|
||||
// nothing to do here
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException("called with unknown loader id!");
|
||||
}
|
||||
@@ -218,7 +228,20 @@ class CreateSecurityTokenImportPresenter {
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -236,5 +259,7 @@ class CreateSecurityTokenImportPresenter {
|
||||
void operationPromote(long masterKeyId, byte[] cardAid);
|
||||
|
||||
void finishAndShowKey(long masterKeyId);
|
||||
|
||||
void showFileSelectDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,16 +18,21 @@
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Request.Builder;
|
||||
import okhttp3.Response;
|
||||
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.KeyserverClient.QueryFailedException;
|
||||
import org.sufficientlysecure.keychain.network.OkHttpClientFactory;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||
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.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeyRepository;
|
||||
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
|
||||
@@ -66,7 +70,7 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
|
||||
KeyRetrievalResult keyRetrievalResult = super.onLoadInBackground();
|
||||
|
||||
try {
|
||||
long elapsedTime = startTime - SystemClock.elapsedRealtime();
|
||||
long elapsedTime = SystemClock.elapsedRealtime() - startTime;
|
||||
if (elapsedTime < MIN_OPERATION_TIME_MILLIS) {
|
||||
Thread.sleep(MIN_OPERATION_TIME_MILLIS - elapsedTime);
|
||||
}
|
||||
@@ -130,8 +134,8 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
|
||||
@Override
|
||||
public KeyRetrievalResult loadInBackground() {
|
||||
try {
|
||||
Response execute =
|
||||
OkHttpClientFactory.getSimpleClient().newCall(new Builder().url(yubikeyUri).build()).execute();
|
||||
Call call = OkHttpClientFactory.getSimpleClient().newCall(new Builder().url(yubikeyUri).build());
|
||||
Response execute = call.execute();
|
||||
if (execute.isSuccessful()) {
|
||||
UncachedKeyRing keyRing = UncachedKeyRing.decodeFromData(execute.body().bytes());
|
||||
if (Arrays.equals(fingerprints[0], keyRing.getFingerprint())) {
|
||||
@@ -162,6 +166,10 @@ public abstract class PublicKeyRetrievalLoader extends AsyncTaskLoader<KeyRetrie
|
||||
|
||||
HkpKeyserverClient keyserverClient = HkpKeyserverClient.fromHkpKeyserverAddress(preferredKeyserver);
|
||||
|
||||
if (true) {
|
||||
return KeyRetrievalResult.createWithError();
|
||||
}
|
||||
|
||||
try {
|
||||
String keyString =
|
||||
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
|
||||
public void deliverResult(KeyRetrievalResult result) {
|
||||
cachedResult = result;
|
||||
|
||||
@@ -1924,5 +1924,6 @@
|
||||
<string name="status_import">Importing key…</string>
|
||||
<string name="status_token_promote">Setting up key…</string>
|
||||
<string name="status_token_check">Checking key setup…</string>
|
||||
<string name="status_content_uri">Reading file…</string>
|
||||
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user