diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java
index 248292c77..89ccd89d9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Parcelable;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
@@ -46,13 +47,13 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
+import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
-import org.sufficientlysecure.keychain.util.FileHelper;
-import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.ParcelableFileCache;
+import org.sufficientlysecure.keychain.util.*;
import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize;
-import org.sufficientlysecure.keychain.util.Preferences;
-import org.sufficientlysecure.keychain.util.ProgressScaler;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
@@ -66,7 +67,13 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.concurrent.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -93,7 +100,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
* TODO rework uploadKeyRingToServer
*/
-public class ImportExportOperation extends BaseOperation {
+public class ImportExportOperation extends BaseOperation {
public ImportExportOperation(Context context, ProviderHelper providerHelper, Progressable progressable) {
super(context, providerHelper, progressable);
@@ -630,15 +637,31 @@ public class ImportExportOperation extends BaseOperation {
}
- public ImportKeyResult importKeys(ArrayList keyList, String keyServer, Context context) {
- Preferences.ProxyPrefs proxyPrefs = Preferences.getPreferences(context).getProxyPrefs();
+ @Override
+ public ImportKeyResult execute(ImportKeyringParcel input, CryptoInputParcel cryptoInput) {
+ Proxy proxy = null;
- Proxy proxy = proxyPrefs.parcelableProxy.getProxy();
+ if (cryptoInput.getParcelableProxy() == null) {
+ // if a proxy is not specified, we retrieve from preferences
+ Preferences.ProxyPrefs proxyPrefs = Preferences.getPreferences(mContext).getProxyPrefs();
+
+ if (proxyPrefs.torEnabled && !OrbotHelper.isOrbotInstalledAndRunning(mContext)) {
+ // is it okay to pass null for log?
+ return new ImportKeyResult(null, RequiredInputParcel.createRequiredOrbotEnable());
+ }
+ } else {
+ proxy = cryptoInput.getParcelableProxy().getProxy();
+ }
+
+ return importKeys(input.mKeyList, input.mKeyserver, proxy);
+ }
+
+ public ImportKeyResult importKeys(ArrayList keyList, String keyServer, Proxy proxy) {
ImportKeyResult result = null;
if (keyList == null) {// import from file, do serially
- ParcelableFileCache cache = new ParcelableFileCache<>(context, "key_import.pcl");
+ ParcelableFileCache cache = new ParcelableFileCache<>(mContext, "key_import.pcl");
result = serialKeyRingImport(cache, keyServer, proxy);
} else {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java
index 1438ad698..6f5c1ca64 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.os.Parcel;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
import org.sufficientlysecure.keychain.ui.LogDisplayFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
@@ -30,7 +31,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
import org.sufficientlysecure.keychain.ui.util.Notify.Showable;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
-public class ImportKeyResult extends OperationResult {
+public class ImportKeyResult extends InputPendingResult {
public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret;
public final long[] mImportedMasterKeyIds;
@@ -79,6 +80,14 @@ public class ImportKeyResult extends OperationResult {
mImportedMasterKeyIds = source.createLongArray();
}
+ /**
+ * Creates a result with attributes other than the log set to defaults.
+ * This constructor is used when the operation fails (including when there is nothing to import) and only the log
+ * and result code matters.
+ *
+ * @param result the result code
+ * @param log
+ */
public ImportKeyResult(int result, OperationLog log) {
this(result, log, 0, 0, 0, 0, new long[] { });
}
@@ -94,6 +103,22 @@ public class ImportKeyResult extends OperationResult {
mImportedMasterKeyIds = importedMasterKeyIds;
}
+ /**
+ * When extra input is required. Super constructor will set the "data pending" field of mResult.
+ *
+ * @param log
+ * @param requiredInput specifies the extra input required
+ */
+ public ImportKeyResult(OperationLog log, RequiredInputParcel requiredInput) {
+ super(log, requiredInput);
+ // just supply default values, we won't use them
+ mNewKeys = 0;
+ mUpdatedKeys = 0;
+ mBadKeys = 0;
+ mSecret = 0;
+ mImportedMasterKeyIds = new long[]{};
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ImportKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ImportKeyringParcel.java
new file mode 100644
index 000000000..9fad0e564
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ImportKeyringParcel.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann
+ * Copyright (C) 2015 Adithya Abraham Philip
+ *
+ * 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 .
+ */
+
+package org.sufficientlysecure.keychain.service;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
+import org.sufficientlysecure.keychain.util.ParcelableProxy;
+
+import java.util.ArrayList;
+
+public class ImportKeyringParcel implements Parcelable {
+ // if null, keys are expected to be read from a cache file in ImportExportOperations
+ public ArrayList mKeyList;
+ public String mKeyserver; // must be set if keys are to be imported from a keyserver
+
+ public ImportKeyringParcel (ArrayList keyList, String keyserver) {
+ mKeyList = keyList;
+ mKeyserver = keyserver;
+ }
+
+ protected ImportKeyringParcel(Parcel in) {
+ if (in.readByte() == 0x01) {
+ mKeyList = new ArrayList<>();
+ in.readList(mKeyList, ParcelableKeyRing.class.getClassLoader());
+ } else {
+ mKeyList = null;
+ }
+ mKeyserver = in.readString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (mKeyList == null) {
+ dest.writeByte((byte) (0x00));
+ } else {
+ dest.writeByte((byte) (0x01));
+ dest.writeList(mKeyList);
+ }
+ dest.writeString(mKeyserver);
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ @Override
+ public ImportKeyringParcel createFromParcel(Parcel in) {
+ return new ImportKeyringParcel(in);
+ }
+
+ @Override
+ public ImportKeyringParcel[] newArray(int size) {
+ return new ImportKeyringParcel[size];
+ }
+ };
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainNewService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainNewService.java
index 9e33a1421..eaf48ddbd 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainNewService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainNewService.java
@@ -31,10 +31,7 @@ import android.os.Parcelable;
import android.os.RemoteException;
import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.operations.BaseOperation;
-import org.sufficientlysecure.keychain.operations.CertifyOperation;
-import org.sufficientlysecure.keychain.operations.EditKeyOperation;
-import org.sufficientlysecure.keychain.operations.SignEncryptOperation;
+import org.sufficientlysecure.keychain.operations.*;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
@@ -103,7 +100,11 @@ public class KeychainNewService extends Service implements Progressable {
op = new EditKeyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
} else if (inputParcel instanceof CertifyAction) {
op = new CertifyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
- } else {
+ } else if (inputParcel instanceof ImportKeyringParcel) {
+ op = new ImportExportOperation(outerThis, new ProviderHelper(outerThis), outerThis,
+ mActionCanceled);
+ }
+ else {
return;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
index b36d31be0..c21454a4c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
@@ -21,11 +21,7 @@ package org.sufficientlysecure.keychain.service;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
+import android.os.*;
import com.textuality.keybase.lib.Proof;
import com.textuality.keybase.lib.prover.Prover;
@@ -394,8 +390,10 @@ public class KeychainService extends Service implements Progressable {
ImportExportOperation importExportOperation = new ImportExportOperation(KeychainService.this,
providerHelper, KeychainService.this, mActionCanceled);
- ImportKeyResult result =
- importExportOperation.importKeys(keyList, keyServer, KeychainService.this);
+ ImportKeyringParcel inputParcel = new ImportKeyringParcel(keyList, keyServer);
+ CryptoInputParcel cryptoInputParcel = new CryptoInputParcel();
+
+ ImportKeyResult result = importExportOperation.execute(inputParcel, cryptoInputParcel);
sendMessageToHandler(MessageStatus.OKAY, result);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
index 3d1ccaca1..925ca4264 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
@@ -26,6 +26,7 @@ import java.util.Map;
import android.os.Parcel;
import android.os.Parcelable;
+import org.sufficientlysecure.keychain.util.ParcelableProxy;
import org.sufficientlysecure.keychain.util.Passphrase;
/**
@@ -40,11 +41,20 @@ public class CryptoInputParcel implements Parcelable {
// used in the crypto operation described by this parcel.
private HashMap mCryptoData = new HashMap<>();
+ // used to specify an explicit proxy for operations that require it
+ private ParcelableProxy mParcelableProxy;
+
public CryptoInputParcel() {
mSignatureTime = new Date();
mPassphrase = null;
}
+ public CryptoInputParcel(ParcelableProxy parcelableProxy) {
+ mSignatureTime = new Date();
+ mPassphrase = null;
+ mParcelableProxy = parcelableProxy;
+ }
+
public CryptoInputParcel(Date signatureTime, Passphrase passphrase) {
mSignatureTime = signatureTime == null ? new Date() : signatureTime;
mPassphrase = passphrase;
@@ -74,6 +84,8 @@ public class CryptoInputParcel implements Parcelable {
}
}
+ mParcelableProxy = source.readParcelable(getClass().getClassLoader());
+
}
@Override
@@ -91,6 +103,8 @@ public class CryptoInputParcel implements Parcelable {
dest.writeByteArray(entry.getKey().array());
dest.writeByteArray(entry.getValue());
}
+
+ dest.writeParcelable(mParcelableProxy, 0);
}
public void addCryptoData(byte[] hash, byte[] signedHash) {
@@ -113,6 +127,10 @@ public class CryptoInputParcel implements Parcelable {
return mPassphrase;
}
+ public ParcelableProxy getParcelableProxy() {
+ return mParcelableProxy;
+ }
+
public static final Creator CREATOR = new Creator() {
public CryptoInputParcel createFromParcel(final Parcel source) {
return new CryptoInputParcel(source);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
index 930c2ee4f..b50bf6fb7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
@@ -12,7 +12,7 @@ import android.os.Parcelable;
public class RequiredInputParcel implements Parcelable {
public enum RequiredInputType {
- PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_KEYTOCARD
+ PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_KEYTOCARD, ENABLE_ORBOT
}
public Date mSignatureTime;
@@ -111,6 +111,10 @@ public class RequiredInputParcel implements Parcelable {
null, null, req.mSignatureTime, req.mMasterKeyId, req.mSubKeyId);
}
+ public static RequiredInputParcel createRequiredOrbotEnable() {
+ return new RequiredInputParcel(RequiredInputType.ENABLE_ORBOT, null, null, null, 0l, 0l);
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
index 45111fc0d..ea0d3a318 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -306,8 +306,7 @@ public class ImportKeysActivity extends BaseNfcActivity {
}
/**
- * loads the CloudFragment, which consists of the search bar, search button and settings icon
- * visually.
+ * loads the CloudFragment, which consists of the search bar, search button and settings icon.
*
* @param savedInstanceState
* @param query search query
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java
new file mode 100644
index 000000000..25fab7938
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann
+ * Copyright (C) 2015 Adithya Abraham Philip
+ *
+ * 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 .
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Preferences;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
+
+/**
+ * Simply encapsulates a dialog. If orbot is not installed, it shows an install dialog, else a dialog to enable orbot.
+ */
+public class OrbotRequiredDialogActivity extends FragmentActivity {
+
+ public final static String RESULT_IGNORE_TOR = "ignore_tor";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ Runnable ignoreTor = new Runnable() {
+ @Override
+ public void run() {
+ Intent data = new Intent();
+ data.putExtra(RESULT_IGNORE_TOR, true);
+ setResult(RESULT_OK, data);
+ }
+ };
+
+ if (OrbotHelper.isOrbotInRequiredState(R.string.orbot_ignore_tor, ignoreTor,
+ Preferences.getPreferences(this).getProxyPrefs(), this)) {
+ Intent data = new Intent();
+ data.putExtra(RESULT_IGNORE_TOR, false);
+ setResult(RESULT_OK, data);
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
index 2be162e95..28d9d4935 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
@@ -36,8 +36,10 @@ import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.NfcOperationActivity;
+import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity;
import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
/**
@@ -48,6 +50,7 @@ public abstract class CryptoOperationFragment