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