tls-psk: actual import of keys

This commit is contained in:
Vincent Breitmoser 2017-05-30 19:06:28 +02:00
parent e44d668e27
commit 703603782f
7 changed files with 139 additions and 63 deletions

View file

@ -124,7 +124,7 @@ public class KeyTransferInteractor {
serverSocket = (SSLServerSocket) sslContext.getServerSocketFactory().createServerSocket(port);
String presharedKeyEncoded = Base64.encodeToString(presharedKey, Base64.URL_SAFE | Base64.NO_PADDING);
String qrCodeData = presharedKeyEncoded + "@" + getIPAddress(true) + ":" + port;
String qrCodeData = "pgp+transfer://" + presharedKeyEncoded + "@" + getIPAddress(true) + ":" + port;
invokeListener(CONNECTION_LISTENING, qrCodeData);
socket = serverSocket.accept();
@ -135,8 +135,8 @@ public class KeyTransferInteractor {
}
handleOpenConnection(socket);
Log.d(Constants.TAG, "connection closed ok!");
} catch (IOException e) {
invokeListener(CONNECTION_LOST, null);
Log.e(Constants.TAG, "error!", e);
} finally {
try {
@ -176,13 +176,8 @@ public class KeyTransferInteractor {
socket.setSoTimeout(500);
while (!isInterrupted() && socket.isConnected()) {
sendDataIfAvailable(socket, outputStream);
boolean connectionClosed = receiveDataIfAvailable(socket, bufferedReader);
if (connectionClosed) {
break;
}
receiveDataIfAvailable(socket, bufferedReader);
}
Log.d(Constants.TAG, "disconnected");
invokeListener(CONNECTION_LOST, null);
}
@ -196,6 +191,7 @@ public class KeyTransferInteractor {
}
if (firstLine == null) {
invokeListener(CONNECTION_LOST, null);
return true;
}
@ -204,7 +200,7 @@ public class KeyTransferInteractor {
socket.setSoTimeout(500);
invokeListener(CONNECTION_RECEIVE_OK, receivedData);
return false;
return true;
}
private boolean sendDataIfAvailable(Socket socket, OutputStream outputStream) throws IOException {

View file

@ -22,6 +22,7 @@ package org.sufficientlysecure.keychain.operations;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
@ -477,7 +478,7 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
@NonNull
@Override
public ImportKeyResult execute(ImportKeyringParcel importInput, CryptoInputParcel cryptoInput) {
ArrayList<ParcelableKeyRing> keyList = importInput.getKeyList();
List<ParcelableKeyRing> keyList = importInput.getKeyList();
HkpKeyserverAddress keyServer = importInput.getKeyserver();
boolean skipSave = importInput.isSkipSave();
@ -510,7 +511,7 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
}
@NonNull
private ImportKeyResult multiThreadedKeyImport(ArrayList<ParcelableKeyRing> keyList,
private ImportKeyResult multiThreadedKeyImport(List<ParcelableKeyRing> keyList,
final HkpKeyserverAddress keyServer, final ParcelableProxy proxy,
final boolean skipSave) {
Log.d(Constants.TAG, "Multi-threaded key import starting");

View file

@ -20,6 +20,8 @@ package org.sufficientlysecure.keychain.service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.os.Parcelable;
import android.support.annotation.Nullable;
@ -31,21 +33,25 @@ import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
@AutoValue
public abstract class ImportKeyringParcel implements Parcelable {
@Nullable // If null, keys are expected to be read from a cache file in ImportExportOperations
public abstract ArrayList<ParcelableKeyRing> getKeyList();
public abstract List<ParcelableKeyRing> getKeyList();
@Nullable // must be set if keys are to be imported from a keyserver
public abstract HkpKeyserverAddress getKeyserver();
public abstract boolean isSkipSave();
public static ImportKeyringParcel createImportKeyringParcel(ArrayList<ParcelableKeyRing> keyList,
public static ImportKeyringParcel createImportKeyringParcel(List<ParcelableKeyRing> keyList,
HkpKeyserverAddress keyserver) {
return new AutoValue_ImportKeyringParcel(keyList, keyserver, false);
}
public static ImportKeyringParcel createWithSkipSave(ArrayList<ParcelableKeyRing> keyList,
public static ImportKeyringParcel createWithSkipSave(List<ParcelableKeyRing> keyList,
HkpKeyserverAddress keyserver) {
return new AutoValue_ImportKeyringParcel(keyList, keyserver, true);
}
public static ImportKeyringParcel createImportKeyringParcel(ParcelableKeyRing key) {
return new AutoValue_ImportKeyringParcel(Collections.singletonList(key), null, false);
}
public static ImportKeyringParcel createFromFileCacheWithSkipSave() {
return new AutoValue_ImportKeyringParcel(null, null, true);
}

View file

@ -27,6 +27,7 @@ import android.net.Uri;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.support.annotation.RequiresApi;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
@ -37,12 +38,18 @@ import android.view.LayoutInflater;
import org.openintents.openpgp.util.OpenPgpUtils;
import org.openintents.openpgp.util.OpenPgpUtils.UserId;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.network.KeyTransferInteractor;
import org.sufficientlysecure.keychain.network.KeyTransferInteractor.KeyTransferCallback;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeyRepository;
import org.sufficientlysecure.keychain.provider.KeyRepository.NotFoundException;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper.Callback;
import org.sufficientlysecure.keychain.ui.transfer.loader.SecretKeyLoader.SecretKeyItem;
import org.sufficientlysecure.keychain.ui.transfer.view.ReceivedSecretKeyList.OnClickImportKeyListener;
import org.sufficientlysecure.keychain.ui.transfer.view.ReceivedSecretKeyList.ReceivedKeyAdapter;
@ -61,11 +68,14 @@ public class TransferPresenter implements KeyTransferCallback, LoaderCallbacks<L
private final LoaderManager loaderManager;
private final int loaderId;
private KeyTransferInteractor keyTransferClientInteractor;
private KeyTransferInteractor keyTransferServerInteractor;
private final TransferKeyAdapter secretKeyAdapter;
private final ReceivedKeyAdapter receivedKeyAdapter;
private KeyTransferInteractor keyTransferClientInteractor;
private KeyTransferInteractor keyTransferServerInteractor;
private boolean wasConnected = false;
public TransferPresenter(Context context, LoaderManager loaderManager, int loaderId, TransferMvpView view) {
this.context = context;
this.view = view;
@ -83,7 +93,7 @@ public class TransferPresenter implements KeyTransferCallback, LoaderCallbacks<L
public void onUiStart() {
loaderManager.restartLoader(loaderId, null, this);
if (keyTransferServerInteractor == null && keyTransferClientInteractor == null) {
if (keyTransferServerInteractor == null && keyTransferClientInteractor == null && !wasConnected) {
connectionStartListen();
}
}
@ -115,26 +125,72 @@ public class TransferPresenter implements KeyTransferCallback, LoaderCallbacks<L
}
@Override
public void onUiClickImportKey(String keyData) {
public void onUiClickImportKey(final long masterKeyId, String keyData) {
receivedKeyAdapter.focusItem(masterKeyId);
final ImportKeyringParcel importKeyringParcel = ImportKeyringParcel.createImportKeyringParcel(
ParcelableKeyRing.createFromEncodedBytes(keyData.getBytes()));
CryptoOperationHelper<ImportKeyringParcel,ImportKeyResult> op =
view.createCryptoOperationHelper(new Callback<ImportKeyringParcel,ImportKeyResult>() {
@Override
public ImportKeyringParcel createOperationInput() {
return importKeyringParcel;
}
@Override
public void onCryptoOperationSuccess(ImportKeyResult result) {
receivedKeyAdapter.focusItem(null);
receivedKeyAdapter.addToFinishedItems(masterKeyId);
view.releaseCryptoOperationHelper();
view.showResultNotification(result);
}
@Override
public void onCryptoOperationCancelled() {
view.releaseCryptoOperationHelper();
receivedKeyAdapter.focusItem(null);
}
@Override
public void onCryptoOperationError(ImportKeyResult result) {
receivedKeyAdapter.focusItem(null);
view.releaseCryptoOperationHelper();
view.showResultNotification(result);
}
@Override
public boolean onCryptoSetProgress(String msg, int progress, int max) {
return false;
}
});
op.cryptoOperation();
}
@Override
public void onServerStarted(String qrCodeData) {
Bitmap qrCodeBitmap = QrCodeUtils.getQRCodeBitmap(Uri.parse("pgp+transfer://" + qrCodeData));
Bitmap qrCodeBitmap = QrCodeUtils.getQRCodeBitmap(Uri.parse(qrCodeData));
view.setQrImage(qrCodeBitmap);
}
@Override
public void onConnectionEstablished(String otherName) {
wasConnected = true;
secretKeyAdapter.clearFinishedItems();
view.showConnectionEstablished(otherName);
}
@Override
public void onConnectionLost() {
connectionStartListen();
if (!wasConnected) {
// display connection error?
connectionStartListen();
view.showErrorConnectionFailed();
}
// TODO handle error?
}
@Override
@ -152,7 +208,8 @@ public class TransferPresenter implements KeyTransferCallback, LoaderCallbacks<L
uncachedKeyRing.getCreationTime(), userId.name, userId.email);
receivedKeyAdapter.addItem(receivedKeyItem);
} catch (PgpGeneralException | IOException e) {
e.printStackTrace();
Log.e(Constants.TAG, "error parsing incoming key", e);
view.showErrorBadKey();
}
}
@ -231,7 +288,15 @@ public class TransferPresenter implements KeyTransferCallback, LoaderCallbacks<L
void scanQrCode();
void setQrImage(Bitmap qrCode);
void releaseCryptoOperationHelper();
void showErrorBadKey();
void showErrorConnectionFailed();
void showResultNotification(ImportKeyResult result);
void setSecretKeyAdapter(Adapter adapter);
void setReceivedKeyAdapter(Adapter secretKeyAdapter);
<T extends Parcelable, S extends OperationResult> CryptoOperationHelper<T,S> createCryptoOperationHelper(Callback<T, S> callback);
}
}

View file

@ -87,6 +87,11 @@ public class ReceivedSecretKeyList extends RecyclerView {
return data.get(position).masterKeyId;
}
public void addToFinishedItems(long masterKeyId) {
finishedItems.add(masterKeyId);
// doeesn't notify, because it's non-trivial and this is called in conjunction with other refreshing things!
}
public void focusItem(Long masterKeyId) {
focusedMasterKeyId = masterKeyId;
notifyItemRangeChanged(0, getItemCount());
@ -154,7 +159,7 @@ public class ReceivedSecretKeyList extends RecyclerView {
vImportButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onClickReceiveKeyListener.onUiClickImportKey(item.keyData);
onClickReceiveKeyListener.onUiClickImportKey(item.masterKeyId, item.keyData);
}
});
} else {
@ -164,7 +169,7 @@ public class ReceivedSecretKeyList extends RecyclerView {
}
public interface OnClickImportKeyListener {
void onUiClickImportKey(String keyData);
void onUiClickImportKey(long masterKeyId, String keyData);
}
public static class ReceivedKeyItem {

View file

@ -18,16 +18,12 @@
package org.sufficientlysecure.keychain.ui.transfer.view;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v4.app.Fragment;
@ -44,8 +40,12 @@ import android.widget.ViewAnimator;
import com.google.zxing.client.android.Intents;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.QrCodeCaptureActivity;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper.Callback;
import org.sufficientlysecure.keychain.ui.transfer.presenter.TransferPresenter;
import org.sufficientlysecure.keychain.ui.transfer.presenter.TransferPresenter.TransferMvpView;
@ -54,8 +54,7 @@ import org.sufficientlysecure.keychain.ui.transfer.presenter.TransferPresenter.T
public class TransferFragment extends Fragment implements TransferMvpView {
public static final int VIEW_WAITING = 0;
public static final int VIEW_CONNECTED = 1;
public static final int VIEW_SEND_OK = 2;
public static final int VIEW_RECEIVING = 3;
public static final int VIEW_RECEIVING = 2;
public static final int REQUEST_CODE_SCAN = 1;
public static final int LOADER_ID = 1;
@ -68,6 +67,8 @@ public class TransferFragment extends Fragment implements TransferMvpView {
private RecyclerView vTransferKeyList;
private RecyclerView vReceivedKeyList;
private CryptoOperationHelper currentCryptoOperationHelper;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -90,15 +91,9 @@ public class TransferFragment extends Fragment implements TransferMvpView {
}
});
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
presenter = new TransferPresenter(getContext(), getLoaderManager(), LOADER_ID, this);
return view;
}
@Override
@ -162,8 +157,40 @@ public class TransferFragment extends Fragment implements TransferMvpView {
vReceivedKeyList.setAdapter(adapter);
}
@Override
public <T extends Parcelable, S extends OperationResult> CryptoOperationHelper<T,S> createCryptoOperationHelper(Callback<T, S> callback) {
CryptoOperationHelper<T,S> cryptoOperationHelper = new CryptoOperationHelper<>(1, this, callback, null);
currentCryptoOperationHelper = cryptoOperationHelper;
return cryptoOperationHelper;
}
@Override
public void releaseCryptoOperationHelper() {
currentCryptoOperationHelper = null;
}
@Override
public void showErrorBadKey() {
}
@Override
public void showErrorConnectionFailed() {
}
@Override
public void showResultNotification(ImportKeyResult result) {
result.createNotify(getActivity()).show(this);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (currentCryptoOperationHelper != null &&
currentCryptoOperationHelper.handleActivityResult(requestCode, resultCode, data)) {
return;
}
switch (requestCode) {
case REQUEST_CODE_SCAN:
if (resultCode == Activity.RESULT_OK) {

View file

@ -87,30 +87,6 @@
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="32dp"
android:layout_marginBottom="32dp"
android:text="Key transfer ok!"
android:textAppearance="?android:attr/textAppearanceMedium" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Finish"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"