From 4499caef1e64d2e1afec37d360958f516da4dd40 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 18 Mar 2015 13:45:16 +0100 Subject: introduce CryptoOperationParcel for nfc data --- .../java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index 9cb4e5f65..049c6976d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -66,6 +66,8 @@ import org.sufficientlysecure.keychain.util.Preferences; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Date; + public class CertifyKeyFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks { @@ -368,7 +370,7 @@ public class CertifyKeyFragment extends LoaderFragment Bundle data = new Bundle(); { // fill values for this action - CertifyActionsParcel parcel = new CertifyActionsParcel(mSignMasterKeyId); + CertifyActionsParcel parcel = new CertifyActionsParcel(new Date(), mSignMasterKeyId); parcel.mCertifyActions.addAll(certifyActions); data.putParcelable(KeychainIntentService.CERTIFY_PARCEL, parcel); -- cgit v1.2.3 From aca54e31eae450e7deec54cca6654ee202c7a90f Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 18 Mar 2015 18:25:44 +0100 Subject: generalize nfc crypto input structure --- .../keychain/ui/EncryptActivity.java | 49 +- .../keychain/ui/EncryptFilesActivity.java | 1 - .../keychain/ui/EncryptTextActivity.java | 1 - .../keychain/ui/NfcOperationActivity.java | 492 +++++++++++++++++++++ 4 files changed, 519 insertions(+), 24 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 35dfcb87c..75f22f01c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -25,15 +25,15 @@ import android.os.Message; import android.os.Messenger; import android.view.View; -import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel; -import java.util.Date; public abstract class EncryptActivity extends BaseActivity { @@ -42,8 +42,6 @@ public abstract class EncryptActivity extends BaseActivity { // For NFC data protected String mSigningKeyPassphrase = null; - protected Date mNfcTimestamp = null; - protected byte[] mNfcHash = null; @Override public void onCreate(Bundle savedInstanceState) { @@ -64,17 +62,12 @@ public abstract class EncryptActivity extends BaseActivity { startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); } - protected void startNfcSign(long keyId, String pin, byte[] hashToSign, int hashAlgo) { - // build PendingIntent for Yubikey NFC operations - Intent intent = new Intent(this, NfcActivity.class); - intent.setAction(NfcActivity.ACTION_SIGN_HASH); + protected void startNfcSign(long keyId, String pin, NfcOperationsParcel nfcOps) { - // pass params through to activity that it can be returned again later to repeat pgp operation - intent.putExtra(NfcActivity.EXTRA_DATA, new Intent()); // not used, only relevant to OpenPgpService - intent.putExtra(NfcActivity.EXTRA_KEY_ID, keyId); - intent.putExtra(NfcActivity.EXTRA_PIN, pin); - intent.putExtra(NfcActivity.EXTRA_NFC_HASH_TO_SIGN, hashToSign); - intent.putExtra(NfcActivity.EXTRA_NFC_HASH_ALGO, hashAlgo); + Intent intent = new Intent(this, NfcOperationActivity.class); + intent.putExtra(NfcOperationActivity.EXTRA_PIN, pin); + intent.putExtra(NfcOperationActivity.EXTRA_NFC_OPS, nfcOps); + // TODO respect keyid(?) startActivityForResult(intent, REQUEST_CODE_NFC); } @@ -93,8 +86,9 @@ public abstract class EncryptActivity extends BaseActivity { case REQUEST_CODE_NFC: { if (resultCode == RESULT_OK && data != null) { - mNfcHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH); - startEncrypt(); + CryptoInputParcel cryptoInput = + data.getParcelableExtra(NfcOperationActivity.RESULT_DATA); + startEncrypt(cryptoInput); return; } break; @@ -108,6 +102,10 @@ public abstract class EncryptActivity extends BaseActivity { } public void startEncrypt() { + startEncrypt(null); + } + + public void startEncrypt(CryptoInputParcel cryptoInput) { if (!inputIsValid()) { // Notify was created by inputIsValid. return; @@ -117,8 +115,13 @@ public abstract class EncryptActivity extends BaseActivity { Intent intent = new Intent(this, KeychainIntentService.class); intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); + final SignEncryptParcel input = createEncryptBundle(); + if (cryptoInput != null) { + input.setCryptoInput(cryptoInput); + } + Bundle data = new Bundle(); - data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, createEncryptBundle()); + data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Message is received after encrypting is done in KeychainIntentService @@ -141,9 +144,13 @@ public abstract class EncryptActivity extends BaseActivity { } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == PgpSignEncryptResult.RESULT_PENDING_NFC) { - mNfcTimestamp = pgpResult.getNfcTimestamp(); - startNfcSign(pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), - pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); + NfcOperationsParcel parcel = NfcOperationsParcel.createNfcSignOperation( + pgpResult.getNfcHash(), + pgpResult.getNfcAlgo(), + input.getSignatureTime()); + startNfcSign(pgpResult.getNfcKeyId(), + pgpResult.getNfcPassphrase(), parcel); + } else { throw new RuntimeException("Unhandled pending result!"); } @@ -158,8 +165,6 @@ public abstract class EncryptActivity extends BaseActivity { // no matter the result, reset parameters mSigningKeyPassphrase = null; - mNfcHash = null; - mNfcTimestamp = null; } } }; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java index f1784fab3..49a0f5016 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -252,7 +252,6 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi data.setEncryptionMasterKeyIds(mEncryptionKeyIds); data.setSignatureMasterKeyId(mSigningKeyId); data.setSignaturePassphrase(mSigningKeyPassphrase); - data.setNfcState(mNfcHash, mNfcTimestamp); } return data; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 14f2c492d..894c1202d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -232,7 +232,6 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv data.setEncryptionMasterKeyIds(mEncryptionKeyIds); data.setSignatureMasterKeyId(mSigningKeyId); data.setSignaturePassphrase(mSigningKeyPassphrase); - data.setNfcState(mNfcHash, mNfcTimestamp); } return data; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java new file mode 100644 index 000000000..c1403d748 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -0,0 +1,492 @@ +/** + * Copyright (c) 2013-2014 Philipp Jakubeit, Signe Rüsch, Dominik Schürmann + * + * Licensed under the Bouncy Castle License (MIT license). See LICENSE file for details. + */ + +package org.sufficientlysecure.keychain.ui; + +import android.annotation.TargetApi; +import android.app.PendingIntent; +import android.content.Intent; +import android.content.IntentFilter; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.nfc.tech.IsoDep; +import android.os.Build; +import android.os.Bundle; +import android.view.WindowManager; +import android.widget.Toast; + +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.util.encoders.Hex; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel; +import org.sufficientlysecure.keychain.util.Iso7816TLV; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.IOException; +import java.nio.ByteBuffer; + + +/** + * This class provides a communication interface to OpenPGP applications on ISO SmartCard compliant + * NFC devices. + * + * For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf + */ +@TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) +public class NfcOperationActivity extends BaseActivity { + + public static final String EXTRA_PIN = "pin"; + public static final String EXTRA_NFC_OPS = "nfc_operations"; + + public static final String RESULT_DATA = "result_data"; + + private static final int TIMEOUT = 100000; + + private NfcAdapter mNfcAdapter; + private IsoDep mIsoDep; + + private String mPin; + + NfcOperationsParcel mNfcOperations; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.d(Constants.TAG, "NfcOperationActivity.onCreate"); + + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + Intent intent = getIntent(); + String action = intent.getAction(); + if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { + throw new AssertionError("should not happen: NfcOperationActivity.onCreate is called instead of onNewIntent!"); + } + + Bundle data = intent.getExtras(); + + mNfcOperations = data.getParcelable(EXTRA_NFC_OPS); + mPin = data.getString(EXTRA_PIN); + + } + + @Override + protected void initLayout() { + setContentView(R.layout.nfc_activity); + } + + /** + * Called when the system is about to start resuming a previous activity, + * disables NFC Foreground Dispatch + */ + public void onPause() { + super.onPause(); + Log.d(Constants.TAG, "NfcOperationActivity.onPause"); + + disableNfcForegroundDispatch(); + } + + /** + * Called when the activity will start interacting with the user, + * enables NFC Foreground Dispatch + */ + public void onResume() { + super.onResume(); + Log.d(Constants.TAG, "NfcOperationActivity.onResume"); + + enableNfcForegroundDispatch(); + } + + /** + * This activity is started as a singleTop activity. + * All new NFC Intents which are delivered to this activity are handled here + */ + public void onNewIntent(Intent intent) { + if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { + try { + handleNdefDiscoveredIntent(intent); + } catch (IOException e) { + Log.e(Constants.TAG, "Connection error!", e); + toast("Connection Error: " + e.getMessage()); + setResult(RESULT_CANCELED); + finish(); + } + } + } + + /** Handle NFC communication and return a result. + * + * This method is called by onNewIntent above upon discovery of an NFC tag. + * It handles initialization and login to the application, subsequently + * calls either nfcCalculateSignature() or nfcDecryptSessionKey(), then + * finishes the activity with an appropiate result. + * + * On general communication, see also + * http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_annex-a.aspx + * + * References to pages are generally related to the OpenPGP Application + * on ISO SmartCard Systems specification. + * + */ + private void handleNdefDiscoveredIntent(Intent intent) throws IOException { + + Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + + // Connect to the detected tag, setting a couple of settings + mIsoDep = IsoDep.get(detectedTag); + mIsoDep.setTimeout(TIMEOUT); // timeout is set to 100 seconds to avoid cancellation during calculation + mIsoDep.connect(); + + // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. + // See specification, page 51 + String accepted = "9000"; + + // Command APDU (page 51) for SELECT FILE command (page 29) + String opening = + "00" // CLA + + "A4" // INS + + "04" // P1 + + "00" // P2 + + "06" // Lc (number of bytes) + + "D27600012401" // Data (6 bytes) + + "00"; // Le + if ( ! card(opening).equals(accepted)) { // activate connection + toast("Opening Error!"); + setResult(RESULT_CANCELED); + finish(); + return; + } + + // Command APDU for VERIFY command (page 32) + String login = + "00" // CLA + + "20" // INS + + "00" // P1 + + "82" // P2 (PW1) + + String.format("%02x", mPin.length()) // Lc + + Hex.toHexString(mPin.getBytes()); + if ( ! card(login).equals(accepted)) { // login + toast("Wrong PIN!"); + setResult(RESULT_CANCELED); + finish(); + return; + } + + CryptoInputParcel resultData = new CryptoInputParcel(mNfcOperations.mSignatureTime); + + switch (mNfcOperations.mType) { + + case NFC_DECRYPT: + + for (int i = 0; i < mNfcOperations.mInputHash.length; i++) { + byte[] hash = mNfcOperations.mInputHash[i]; + byte[] decryptedSessionKey = nfcDecryptSessionKey(hash); + resultData.addCryptoData(hash, decryptedSessionKey); + } + break; + + case NFC_SIGN: + for (int i = 0; i < mNfcOperations.mInputHash.length; i++) { + byte[] hash = mNfcOperations.mInputHash[i]; + int algo = mNfcOperations.mSignAlgo[i]; + byte[] signedHash = nfcCalculateSignature(hash, algo); + resultData.addCryptoData(hash, signedHash); + } + break; + } + + // give data through for new service call + Intent result = new Intent(); + result.putExtra(RESULT_DATA, resultData); + setResult(RESULT_OK, result); + finish(); + + } + + /** + * Gets the user ID + * + * @return the user id as "name " + * @throws java.io.IOException + */ + public String getUserId() throws IOException { + String info = "00CA006500"; + String data = "00CA005E00"; + return getName(card(info)) + " <" + (new String(Hex.decode(getDataField(card(data))))) + ">"; + } + + /** Return the key id from application specific data stored on tag, or null + * if it doesn't exist. + * + * @param idx Index of the key to return the fingerprint from. + * @return The long key id of the requested key, or null if not found. + */ + public static Long nfcGetKeyId(IsoDep isoDep, int idx) throws IOException { + byte[] fp = nfcGetFingerprint(isoDep, idx); + if (fp == null) { + return null; + } + ByteBuffer buf = ByteBuffer.wrap(fp); + // skip first 12 bytes of the fingerprint + buf.position(12); + // the last eight bytes are the key id (big endian, which is default order in ByteBuffer) + return buf.getLong(); + } + + /** Return fingerprints of all keys from application specific data stored + * on tag, or null if data not available. + * + * @return The fingerprints of all subkeys in a contiguous byte array. + */ + public static byte[] nfcGetFingerprints(IsoDep isoDep) throws IOException { + String data = "00CA006E00"; + byte[] buf = isoDep.transceive(Hex.decode(data)); + + Iso7816TLV tlv = Iso7816TLV.readSingle(buf, true); + Log.d(Constants.TAG, "nfc tlv data:\n" + tlv.prettyPrint()); + + Iso7816TLV fptlv = Iso7816TLV.findRecursive(tlv, 0xc5); + if (fptlv == null) { + return null; + } + + return fptlv.mV; + } + + /** Return the fingerprint from application specific data stored on tag, or + * null if it doesn't exist. + * + * @param idx Index of the key to return the fingerprint from. + * @return The fingerprint of the requested key, or null if not found. + */ + public static byte[] nfcGetFingerprint(IsoDep isoDep, int idx) throws IOException { + byte[] data = nfcGetFingerprints(isoDep); + + // return the master key fingerprint + ByteBuffer fpbuf = ByteBuffer.wrap(data); + byte[] fp = new byte[20]; + fpbuf.position(idx*20); + fpbuf.get(fp, 0, 20); + + return fp; + } + + /** + * Calls to calculate the signature and returns the MPI value + * + * @param hash the hash for signing + * @return a big integer representing the MPI for the given hash + * @throws java.io.IOException + */ + public byte[] nfcCalculateSignature(byte[] hash, int hashAlgo) throws IOException { + + // dsi, including Lc + String dsi; + + Log.i(Constants.TAG, "Hash: " + hashAlgo); + switch (hashAlgo) { + case HashAlgorithmTags.SHA1: + if (hash.length != 20) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 10!"); + } + dsi = "23" // Lc + + "3021" // Tag/Length of Sequence, the 0x21 includes all following 33 bytes + + "3009" // Tag/Length of Sequence, the 0x09 are the following header bytes + + "0605" + "2B0E03021A" // OID of SHA1 + + "0500" // TLV coding of ZERO + + "0414" + getHex(hash); // 0x14 are 20 hash bytes + break; + case HashAlgorithmTags.RIPEMD160: + if (hash.length != 20) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 20!"); + } + dsi = "233021300906052B2403020105000414" + getHex(hash); + break; + case HashAlgorithmTags.SHA224: + if (hash.length != 28) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 28!"); + } + dsi = "2F302D300D06096086480165030402040500041C" + getHex(hash); + break; + case HashAlgorithmTags.SHA256: + if (hash.length != 32) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 32!"); + } + dsi = "333031300D060960864801650304020105000420" + getHex(hash); + break; + case HashAlgorithmTags.SHA384: + if (hash.length != 48) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 48!"); + } + dsi = "433041300D060960864801650304020205000430" + getHex(hash); + break; + case HashAlgorithmTags.SHA512: + if (hash.length != 64) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 64!"); + } + dsi = "533051300D060960864801650304020305000440" + getHex(hash); + break; + default: + throw new RuntimeException("Not supported hash algo!"); + } + + // Command APDU for PERFORM SECURITY OPERATION: COMPUTE DIGITAL SIGNATURE (page 37) + String apdu = + "002A9E9A" // CLA, INS, P1, P2 + + dsi // digital signature input + + "00"; // Le + + String response = card(apdu); + + // split up response into signature and status + String status = response.substring(response.length()-4); + String signature = response.substring(0, response.length() - 4); + + // while we are getting 0x61 status codes, retrieve more data + while (status.substring(0, 2).equals("61")) { + Log.d(Constants.TAG, "requesting more data, status " + status); + // Send GET RESPONSE command + response = card("00C00000" + status.substring(2)); + status = response.substring(response.length()-4); + signature += response.substring(0, response.length()-4); + } + + Log.d(Constants.TAG, "final response:" + status); + + if ( ! status.equals("9000")) { + toast("Bad NFC response code: " + status); + return null; + } + + // Make sure the signature we received is actually the expected number of bytes long! + if (signature.length() != 256 && signature.length() != 512) { + toast("Bad signature length! Expected 128 or 256 bytes, got " + signature.length() / 2); + return null; + } + + return Hex.decode(signature); + } + + /** + * Calls to calculate the signature and returns the MPI value + * + * @param encryptedSessionKey the encoded session key + * @return the decoded session key + * @throws java.io.IOException + */ + public byte[] nfcDecryptSessionKey(byte[] encryptedSessionKey) throws IOException { + String firstApdu = "102a8086fe"; + String secondApdu = "002a808603"; + String le = "00"; + + byte[] one = new byte[254]; + // leave out first byte: + System.arraycopy(encryptedSessionKey, 1, one, 0, one.length); + + byte[] two = new byte[encryptedSessionKey.length - 1 - one.length]; + for (int i = 0; i < two.length; i++) { + two[i] = encryptedSessionKey[i + one.length + 1]; + } + + String first = card(firstApdu + getHex(one)); + String second = card(secondApdu + getHex(two) + le); + + String decryptedSessionKey = getDataField(second); + + Log.d(Constants.TAG, "decryptedSessionKey: " + decryptedSessionKey); + + return Hex.decode(decryptedSessionKey); + } + + /** + * Prints a message to the screen + * + * @param text the text which should be contained within the toast + */ + private void toast(String text) { + Toast.makeText(this, text, Toast.LENGTH_LONG).show(); + } + + /** + * Receive new NFC Intents to this activity only by enabling foreground dispatch. + * This can only be done in onResume! + */ + public void enableNfcForegroundDispatch() { + mNfcAdapter = NfcAdapter.getDefaultAdapter(this); + Intent nfcI = new Intent(this, NfcOperationActivity.class) + .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + PendingIntent nfcPendingIntent = PendingIntent.getActivity(this, 0, nfcI, PendingIntent.FLAG_CANCEL_CURRENT); + IntentFilter[] writeTagFilters = new IntentFilter[]{ + new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED) + }; + + // https://code.google.com/p/android/issues/detail?id=62918 + // maybe mNfcAdapter.enableReaderMode(); ? + try { + mNfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null); + } catch (IllegalStateException e) { + Log.i(Constants.TAG, "NfcForegroundDispatch Error!", e); + } + Log.d(Constants.TAG, "NfcForegroundDispatch has been enabled!"); + } + + /** + * Disable foreground dispatch in onPause! + */ + public void disableNfcForegroundDispatch() { + mNfcAdapter.disableForegroundDispatch(this); + Log.d(Constants.TAG, "NfcForegroundDispatch has been disabled!"); + } + + /** + * Gets the name of the user out of the raw card output regarding card holder related data + * + * @param name the raw card holder related data from the card + * @return the name given in this data + */ + public String getName(String name) { + String slength; + int ilength; + name = name.substring(6); + slength = name.substring(0, 2); + ilength = Integer.parseInt(slength, 16) * 2; + name = name.substring(2, ilength + 2); + name = (new String(Hex.decode(name))).replace('<', ' '); + return (name); + } + + /** + * Reduces the raw data from the card by four characters + * + * @param output the raw data from the card + * @return the data field of that data + */ + private String getDataField(String output) { + return output.substring(0, output.length() - 4); + } + + /** + * Communicates with the OpenPgpCard via the APDU + * + * @param hex the hexadecimal APDU + * @return The answer from the card + * @throws java.io.IOException throws an exception if something goes wrong + */ + public String card(String hex) throws IOException { + return getHex(mIsoDep.transceive(Hex.decode(hex))); + } + + /** + * Converts a byte array into an hex string + * + * @param raw the byte array representation + * @return the hexadecimal string representation + */ + public static String getHex(byte[] raw) { + return new String(Hex.encode(raw)); + } +} -- cgit v1.2.3 From d46fc3740bbfc3bac0b1133a3e9d47c7ce3e06e2 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 18 Mar 2015 21:12:31 +0100 Subject: yubikey certifications! --- .../keychain/ui/CertifyKeyFragment.java | 80 ++++++------------- .../keychain/ui/CryptoOperationFragment.java | 89 ++++++++++++++++++++++ .../keychain/ui/NfcOperationActivity.java | 10 +-- 3 files changed, 117 insertions(+), 62 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index 049c6976d..acb6b0b85 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -56,7 +56,7 @@ import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner; @@ -66,14 +66,11 @@ import org.sufficientlysecure.keychain.util.Preferences; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Date; -public class CertifyKeyFragment extends LoaderFragment +public class CertifyKeyFragment extends CryptoOperationFragment implements LoaderManager.LoaderCallbacks { - public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; - private CheckBox mUploadKeyCheckbox; ListView mUserIds; @@ -102,9 +99,6 @@ public class CertifyKeyFragment extends LoaderFragment public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - // Start out with a progress indicator. - setContentShown(false); - mPubMasterKeyIds = getActivity().getIntent().getLongArrayExtra(CertifyKeyActivity.EXTRA_KEY_IDS); if (mPubMasterKeyIds == null) { Log.e(Constants.TAG, "List of key ids to certify missing!"); @@ -114,6 +108,7 @@ public class CertifyKeyFragment extends LoaderFragment mPassthroughMessenger = getActivity().getIntent().getParcelableExtra( KeychainIntentService.EXTRA_MESSENGER); + mPassthroughMessenger = null; // TODO remove, development hack // preselect certify key id if given long certifyKeyId = getActivity().getIntent().getLongExtra(CertifyKeyActivity.EXTRA_CERTIFY_KEY_ID, Constants.key.none); @@ -143,9 +138,7 @@ public class CertifyKeyFragment extends LoaderFragment @Override public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { - View root = super.onCreateView(inflater, superContainer, savedInstanceState); - - View view = inflater.inflate(R.layout.certify_key_fragment, getContainer()); + View view = inflater.inflate(R.layout.certify_key_fragment, null); mCertifyKeySpinner = (CertifyKeySpinner) view.findViewById(R.id.certify_key_spinner); mUploadKeyCheckbox = (CheckBox) view.findViewById(R.id.sign_key_upload_checkbox); @@ -173,7 +166,7 @@ public class CertifyKeyFragment extends LoaderFragment Notify.showNotify(getActivity(), getString(R.string.select_key_to_certify), Notify.Style.ERROR); } else { - initiateCertifying(); + cryptoOperation(); } } }); @@ -183,7 +176,7 @@ public class CertifyKeyFragment extends LoaderFragment mUploadKeyCheckbox.setChecked(false); } - return root; + return view; } @Override @@ -307,7 +300,6 @@ public class CertifyKeyFragment extends LoaderFragment } mUserIdsAdapter.swapCursor(matrix); - setContentShown(true, isResumed()); } @Override @@ -315,50 +307,17 @@ public class CertifyKeyFragment extends LoaderFragment mUserIdsAdapter.swapCursor(null); } - /** - * handles the UI bits of the signing process on the UI thread - */ - private void initiateCertifying() { - // get the user's passphrase for this key (if required) - String passphrase; - try { - passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), mSignMasterKeyId, mSignMasterKeyId); - } catch (PassphraseCacheService.KeyNotFoundException e) { - Log.e(Constants.TAG, "Key not found!", e); - getActivity().finish(); - return; - } - if (passphrase == null) { - Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); - intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, mSignMasterKeyId); - startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); - // bail out; need to wait until the user has entered the passphrase before trying again - } else { - startCertifying(); - } + protected void cryptoOperation() { + cryptoOperation((CryptoInputParcel) null); } @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CODE_PASSPHRASE: { - if (resultCode == Activity.RESULT_OK && data != null) { - String passphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); - startCertifying(); - } - return; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - } - } + protected void cryptoOperation(String passphrase) { + cryptoOperation((CryptoInputParcel) null); } - /** - * kicks off the actual signing process on a background thread - */ - private void startCertifying() { + @Override + protected void cryptoOperation(CryptoInputParcel cryptoInput) { // Bail out if there is not at least one user id selected ArrayList certifyActions = mUserIdsAdapter.getSelectedCertifyActions(); if (certifyActions.isEmpty()) { @@ -370,7 +329,7 @@ public class CertifyKeyFragment extends LoaderFragment Bundle data = new Bundle(); { // fill values for this action - CertifyActionsParcel parcel = new CertifyActionsParcel(new Date(), mSignMasterKeyId); + CertifyActionsParcel parcel = new CertifyActionsParcel(cryptoInput, mSignMasterKeyId); parcel.mCertifyActions.addAll(certifyActions); data.putParcelable(KeychainIntentService.CERTIFY_PARCEL, parcel); @@ -390,14 +349,21 @@ public class CertifyKeyFragment extends LoaderFragment } else { // Message is received after signing is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), - getString(R.string.progress_certifying), ProgressDialog.STYLE_SPINNER, true) { + KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( + getActivity(), getString(R.string.progress_certifying), + ProgressDialog.STYLE_SPINNER, true) { public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first + // handle messages by KeychainIntentCryptoServiceHandler first super.handleMessage(message); + // handle pending messages + if (handlePendingMessage(message)) { + return; + } + if (message.arg1 == MessageStatus.OKAY.ordinal()) { Bundle data = message.getData(); + CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT); Intent intent = new Intent(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java new file mode 100644 index 000000000..a1d70b011 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java @@ -0,0 +1,89 @@ +package org.sufficientlysecure.keychain.ui; + + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Message; +import android.support.v4.app.Fragment; + +import org.sufficientlysecure.keychain.operations.results.CertifyResult; +import org.sufficientlysecure.keychain.operations.results.InputPendingResult; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel; + + +public abstract class CryptoOperationFragment extends Fragment { + + public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; + public static final int REQUEST_CODE_NFC = 0x00008002; + + private void startPassphraseDialog(long subkeyId) { + Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); + intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId); + startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); + } + + private void initiateNfcInput(NfcOperationsParcel nfcOps) { + Intent intent = new Intent(getActivity(), NfcOperationActivity.class); + intent.putExtra(NfcOperationActivity.EXTRA_PIN, "123456"); + intent.putExtra(NfcOperationActivity.EXTRA_NFC_OPS, nfcOps); + startActivityForResult(intent, REQUEST_CODE_NFC); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case REQUEST_CODE_PASSPHRASE: { + if (resultCode == Activity.RESULT_OK && data != null) { + String passphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); + cryptoOperation(passphrase); + } + return; + } + + case REQUEST_CODE_NFC: { + if (resultCode == Activity.RESULT_OK && data != null) { + CryptoInputParcel cryptoInput = + data.getParcelableExtra(NfcOperationActivity.RESULT_DATA); + cryptoOperation(cryptoInput); + return; + } + break; + } + + default: { + super.onActivityResult(requestCode, resultCode, data); + } + } + } + + public boolean handlePendingMessage(Message message) { + + if (message.arg1 == MessageStatus.OKAY.ordinal()) { + Bundle data = message.getData(); + + InputPendingResult result = data.getParcelable(CertifyResult.EXTRA_RESULT); + + if (result != null && result.isPending()) { + if (result.isPassphrasePending()) { + startPassphraseDialog(result.getPassphraseKeyId()); + return true; + } else if (result.isNfcPending()) { + NfcOperationsParcel requiredInput = result.getNfcOperationsParcel(); + initiateNfcInput(requiredInput); + return true; + } else { + throw new RuntimeException("Unhandled pending result!"); + } + } + } + + return false; + } + + protected abstract void cryptoOperation(CryptoInputParcel cryptoInput); + protected abstract void cryptoOperation(String passphrase); + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index c1403d748..f226e71c0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -182,17 +182,17 @@ public class NfcOperationActivity extends BaseActivity { case NFC_DECRYPT: - for (int i = 0; i < mNfcOperations.mInputHash.length; i++) { - byte[] hash = mNfcOperations.mInputHash[i]; + for (int i = 0; i < mNfcOperations.mInputHashes.length; i++) { + byte[] hash = mNfcOperations.mInputHashes[i]; byte[] decryptedSessionKey = nfcDecryptSessionKey(hash); resultData.addCryptoData(hash, decryptedSessionKey); } break; case NFC_SIGN: - for (int i = 0; i < mNfcOperations.mInputHash.length; i++) { - byte[] hash = mNfcOperations.mInputHash[i]; - int algo = mNfcOperations.mSignAlgo[i]; + for (int i = 0; i < mNfcOperations.mInputHashes.length; i++) { + byte[] hash = mNfcOperations.mInputHashes[i]; + int algo = mNfcOperations.mSignAlgos[i]; byte[] signedHash = nfcCalculateSignature(hash, algo); resultData.addCryptoData(hash, signedHash); } -- cgit v1.2.3 From 25d89b5550b7fd699988954b07cad61bee9a8ba5 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 19 Mar 2015 14:21:30 +0100 Subject: generalize NfcOperationParcel to RequiredInputParcel, including passphrases --- .../keychain/ui/CertifyKeyFragment.java | 11 +---- .../keychain/ui/CryptoOperationFragment.java | 52 ++++++++++++---------- .../keychain/ui/EncryptActivity.java | 8 ++-- .../keychain/ui/NfcOperationActivity.java | 8 ++-- .../keychain/ui/PassphraseDialogActivity.java | 18 +++++++- 5 files changed, 54 insertions(+), 43 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index acb6b0b85..711e2f2e7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -166,7 +166,7 @@ public class CertifyKeyFragment extends CryptoOperationFragment Notify.showNotify(getActivity(), getString(R.string.select_key_to_certify), Notify.Style.ERROR); } else { - cryptoOperation(); + cryptoOperation(null); } } }); @@ -307,15 +307,6 @@ public class CertifyKeyFragment extends CryptoOperationFragment mUserIdsAdapter.swapCursor(null); } - protected void cryptoOperation() { - cryptoOperation((CryptoInputParcel) null); - } - - @Override - protected void cryptoOperation(String passphrase) { - cryptoOperation((CryptoInputParcel) null); - } - @Override protected void cryptoOperation(CryptoInputParcel cryptoInput) { // Bail out if there is not at least one user id selected diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java index a1d70b011..585a9433a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java @@ -11,7 +11,7 @@ import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.operations.results.InputPendingResult; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; public abstract class CryptoOperationFragment extends Fragment { @@ -19,17 +19,28 @@ public abstract class CryptoOperationFragment extends Fragment { public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; public static final int REQUEST_CODE_NFC = 0x00008002; - private void startPassphraseDialog(long subkeyId) { - Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); - intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId); - startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); - } + private void initiateInputActivity(RequiredInputParcel requiredInput) { + + switch (requiredInput.mType) { + case NFC_DECRYPT: + case NFC_SIGN: { + Intent intent = new Intent(getActivity(), NfcOperationActivity.class); + intent.putExtra(NfcOperationActivity.EXTRA_PIN, "123456"); + intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput); + startActivityForResult(intent, REQUEST_CODE_NFC); + return; + } + + case PASSPHRASE: { + Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); + intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput); + startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); + return; + } + } + + throw new RuntimeException("Unhandled pending result!"); - private void initiateNfcInput(NfcOperationsParcel nfcOps) { - Intent intent = new Intent(getActivity(), NfcOperationActivity.class); - intent.putExtra(NfcOperationActivity.EXTRA_PIN, "123456"); - intent.putExtra(NfcOperationActivity.EXTRA_NFC_OPS, nfcOps); - startActivityForResult(intent, REQUEST_CODE_NFC); } @Override @@ -37,8 +48,9 @@ public abstract class CryptoOperationFragment extends Fragment { switch (requestCode) { case REQUEST_CODE_PASSPHRASE: { if (resultCode == Activity.RESULT_OK && data != null) { - String passphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); - cryptoOperation(passphrase); + CryptoInputParcel cryptoInput = + data.getParcelableExtra(PassphraseDialogActivity.RESULT_DATA); + cryptoOperation(cryptoInput); } return; } @@ -67,16 +79,9 @@ public abstract class CryptoOperationFragment extends Fragment { InputPendingResult result = data.getParcelable(CertifyResult.EXTRA_RESULT); if (result != null && result.isPending()) { - if (result.isPassphrasePending()) { - startPassphraseDialog(result.getPassphraseKeyId()); - return true; - } else if (result.isNfcPending()) { - NfcOperationsParcel requiredInput = result.getNfcOperationsParcel(); - initiateNfcInput(requiredInput); - return true; - } else { - throw new RuntimeException("Unhandled pending result!"); - } + RequiredInputParcel requiredInput = result.getRequiredInputParcel(); + initiateInputActivity(requiredInput); + return true; } } @@ -84,6 +89,5 @@ public abstract class CryptoOperationFragment extends Fragment { } protected abstract void cryptoOperation(CryptoInputParcel cryptoInput); - protected abstract void cryptoOperation(String passphrase); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 75f22f01c..f9b8e2ab6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -32,7 +32,7 @@ import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; public abstract class EncryptActivity extends BaseActivity { @@ -62,11 +62,11 @@ public abstract class EncryptActivity extends BaseActivity { startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); } - protected void startNfcSign(long keyId, String pin, NfcOperationsParcel nfcOps) { + protected void startNfcSign(long keyId, String pin, RequiredInputParcel nfcOps) { Intent intent = new Intent(this, NfcOperationActivity.class); intent.putExtra(NfcOperationActivity.EXTRA_PIN, pin); - intent.putExtra(NfcOperationActivity.EXTRA_NFC_OPS, nfcOps); + intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, nfcOps); // TODO respect keyid(?) startActivityForResult(intent, REQUEST_CODE_NFC); @@ -144,7 +144,7 @@ public abstract class EncryptActivity extends BaseActivity { } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == PgpSignEncryptResult.RESULT_PENDING_NFC) { - NfcOperationsParcel parcel = NfcOperationsParcel.createNfcSignOperation( + RequiredInputParcel parcel = RequiredInputParcel.createNfcSignOperation( pgpResult.getNfcHash(), pgpResult.getNfcAlgo(), input.getSignatureTime()); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index f226e71c0..6a83c2361 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -23,7 +23,7 @@ import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; @@ -41,7 +41,7 @@ import java.nio.ByteBuffer; public class NfcOperationActivity extends BaseActivity { public static final String EXTRA_PIN = "pin"; - public static final String EXTRA_NFC_OPS = "nfc_operations"; + public static final String EXTRA_REQUIRED_INPUT = "required_input"; public static final String RESULT_DATA = "result_data"; @@ -52,7 +52,7 @@ public class NfcOperationActivity extends BaseActivity { private String mPin; - NfcOperationsParcel mNfcOperations; + RequiredInputParcel mNfcOperations; @Override protected void onCreate(Bundle savedInstanceState) { @@ -69,7 +69,7 @@ public class NfcOperationActivity extends BaseActivity { Bundle data = intent.getExtras(); - mNfcOperations = data.getParcelable(EXTRA_NFC_OPS); + mNfcOperations = data.getParcelable(EXTRA_REQUIRED_INPUT); mPin = data.getString(EXTRA_PIN); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index 48509710a..ca65f47cd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -41,6 +41,7 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; +import junit.framework.Assert; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; @@ -53,6 +54,9 @@ import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.PassphraseCacheService; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; +import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; @@ -63,7 +67,9 @@ import org.sufficientlysecure.keychain.util.Preferences; */ public class PassphraseDialogActivity extends FragmentActivity { public static final String MESSAGE_DATA_PASSPHRASE = "passphrase"; + public static final String RESULT_DATA = "result_data"; + public static final String EXTRA_REQUIRED_INPUT = "required_input"; public static final String EXTRA_SUBKEY_ID = "secret_key_id"; // special extra for OpenPgpService @@ -86,7 +92,16 @@ public class PassphraseDialogActivity extends FragmentActivity { // this activity itself has no content view (see manifest) - long keyId = getIntent().getLongExtra(EXTRA_SUBKEY_ID, 0); + long keyId; + if (getIntent().hasExtra(EXTRA_SUBKEY_ID)) { + keyId = getIntent().getLongExtra(EXTRA_SUBKEY_ID, 0); + } else { + RequiredInputParcel requiredInput = getIntent().getParcelableExtra(EXTRA_REQUIRED_INPUT); + if (requiredInput.mType != RequiredInputType.PASSPHRASE) { + throw new AssertionError("Wrong required input type for PassphraseDialogActivity!"); + } + keyId = requiredInput.getSubKeyId(); + } Intent serviceIntent = getIntent().getParcelableExtra(EXTRA_DATA); @@ -410,6 +425,7 @@ public class PassphraseDialogActivity extends FragmentActivity { // also return passphrase back to activity Intent returnIntent = new Intent(); returnIntent.putExtra(MESSAGE_DATA_PASSPHRASE, passphrase); + returnIntent.putExtra(RESULT_DATA, new CryptoInputParcel(null, passphrase)); getActivity().setResult(RESULT_OK, returnIntent); } -- cgit v1.2.3 From 3b04636f5daf3d171449296a5d9a67440abfbf75 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 20 Mar 2015 02:27:05 +0100 Subject: support yubikeys in (some) edit key operations --- .../keychain/ui/CryptoOperationFragment.java | 12 ++- .../keychain/ui/EditKeyFragment.java | 86 ++++++---------------- .../keychain/ui/EncryptActivity.java | 6 +- .../keychain/ui/NfcOperationActivity.java | 10 +-- .../ui/dialog/SetPassphraseDialogFragment.java | 12 +-- 5 files changed, 37 insertions(+), 89 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java index 585a9433a..6b67d1db8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java @@ -9,6 +9,7 @@ import android.support.v4.app.Fragment; import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.operations.results.InputPendingResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -25,7 +26,6 @@ public abstract class CryptoOperationFragment extends Fragment { case NFC_DECRYPT: case NFC_SIGN: { Intent intent = new Intent(getActivity(), NfcOperationActivity.class); - intent.putExtra(NfcOperationActivity.EXTRA_PIN, "123456"); intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput); startActivityForResult(intent, REQUEST_CODE_NFC); return; @@ -76,10 +76,14 @@ public abstract class CryptoOperationFragment extends Fragment { if (message.arg1 == MessageStatus.OKAY.ordinal()) { Bundle data = message.getData(); - InputPendingResult result = data.getParcelable(CertifyResult.EXTRA_RESULT); + OperationResult result = data.getParcelable(CertifyResult.EXTRA_RESULT); + if (result == null || ! (result instanceof InputPendingResult)) { + return false; + } - if (result != null && result.isPending()) { - RequiredInputParcel requiredInput = result.getRequiredInputParcel(); + InputPendingResult pendingResult = (InputPendingResult) result; + if (pendingResult.isPending()) { + RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel(); initiateInputActivity(requiredInput); return true; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index 8d16fe47e..9f2fa54f8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -17,6 +17,8 @@ package org.sufficientlysecure.keychain.ui; +import java.util.Date; + import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; @@ -51,10 +53,10 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; @@ -68,14 +70,12 @@ import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; -public class EditKeyFragment extends LoaderFragment implements +public class EditKeyFragment extends CryptoOperationFragment implements LoaderManager.LoaderCallbacks { public static final String ARG_DATA_URI = "uri"; public static final String ARG_SAVE_KEYRING_PARCEL = "save_keyring_parcel"; - public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; - private ListView mUserIdsList; private ListView mSubkeysList; private ListView mUserIdsAddedList; @@ -100,7 +100,6 @@ public class EditKeyFragment extends LoaderFragment implements private SaveKeyringParcel mSaveKeyringParcel; private String mPrimaryUserId; - private String mCurrentPassphrase; /** * Creates new instance of this fragment @@ -129,8 +128,7 @@ public class EditKeyFragment extends LoaderFragment implements @Override public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { - View root = super.onCreateView(inflater, superContainer, savedInstanceState); - View view = inflater.inflate(R.layout.edit_key_fragment, getContainer()); + View view = inflater.inflate(R.layout.edit_key_fragment, null); mUserIdsList = (ListView) view.findViewById(R.id.edit_key_user_ids); mSubkeysList = (ListView) view.findViewById(R.id.edit_key_keys); @@ -140,7 +138,7 @@ public class EditKeyFragment extends LoaderFragment implements mAddUserId = view.findViewById(R.id.edit_key_action_add_user_id); mAddSubkey = view.findViewById(R.id.edit_key_action_add_key); - return root; + return view; } @Override @@ -155,7 +153,7 @@ public class EditKeyFragment extends LoaderFragment implements if (mDataUri == null) { returnKeyringParcel(); } else { - saveInDatabase(mCurrentPassphrase); + cryptoOperation(new CryptoInputParcel(new Date())); } } }, new OnClickListener() { @@ -185,18 +183,12 @@ public class EditKeyFragment extends LoaderFragment implements private void loadSaveKeyringParcel(SaveKeyringParcel saveKeyringParcel) { mSaveKeyringParcel = saveKeyringParcel; mPrimaryUserId = saveKeyringParcel.mChangePrimaryUserId; - if (saveKeyringParcel.mNewUnlock != null) { - mCurrentPassphrase = saveKeyringParcel.mNewUnlock.mNewPassphrase; - } mUserIdsAddedAdapter = new UserIdsAddedAdapter(getActivity(), mSaveKeyringParcel.mAddUserIds, true); mUserIdsAddedList.setAdapter(mUserIdsAddedAdapter); mSubkeysAddedAdapter = new SubkeysAddedAdapter(getActivity(), mSaveKeyringParcel.mAddSubKeys, true); mSubkeysAddedList.setAdapter(mSubkeysAddedAdapter); - - // show directly - setContentShown(true); } private void loadData(Uri dataUri) { @@ -216,9 +208,6 @@ public class EditKeyFragment extends LoaderFragment implements case GNU_DUMMY: finishWithError(LogType.MSG_EK_ERROR_DUMMY); return; - case DIVERT_TO_CARD: - finishWithError(LogType.MSG_EK_ERROR_DIVERT); - break; } mSaveKeyringParcel = new SaveKeyringParcel(masterKeyId, keyRing.getFingerprint()); @@ -229,24 +218,10 @@ public class EditKeyFragment extends LoaderFragment implements return; } - try { - mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), - mSaveKeyringParcel.mMasterKeyId, mSaveKeyringParcel.mMasterKeyId); - } catch (PassphraseCacheService.KeyNotFoundException e) { - finishWithError(LogType.MSG_EK_ERROR_NOT_FOUND); - return; - } - - if (mCurrentPassphrase == null) { - Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); - intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, mSaveKeyringParcel.mMasterKeyId); - startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); - } else { - // Prepare the loaders. Either re-connect with an existing ones, - // or start new ones. - getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, EditKeyFragment.this); - getLoaderManager().initLoader(LOADER_ID_SUBKEYS, null, EditKeyFragment.this); - } + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, EditKeyFragment.this); + getLoaderManager().initLoader(LOADER_ID_SUBKEYS, null, EditKeyFragment.this); mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, mSaveKeyringParcel); mUserIdsList.setAdapter(mUserIdsAdapter); @@ -262,28 +237,6 @@ public class EditKeyFragment extends LoaderFragment implements mSubkeysAddedList.setAdapter(mSubkeysAddedAdapter); } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CODE_PASSPHRASE: { - if (resultCode == Activity.RESULT_OK && data != null) { - mCurrentPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); - // Prepare the loaders. Either re-connect with an existing ones, - // or start new ones. - getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, EditKeyFragment.this); - getLoaderManager().initLoader(LOADER_ID_SUBKEYS, null, EditKeyFragment.this); - } else { - getActivity().finish(); - } - return; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - } - } - } - private void initView() { mChangePassphrase.setOnClickListener(new View.OnClickListener() { @Override @@ -322,7 +275,6 @@ public class EditKeyFragment extends LoaderFragment implements } public Loader onCreateLoader(int id, Bundle args) { - setContentShown(false); switch (id) { case LOADER_ID_USER_IDS: { @@ -355,7 +307,6 @@ public class EditKeyFragment extends LoaderFragment implements break; } - setContentShown(true); } /** @@ -397,7 +348,7 @@ public class EditKeyFragment extends LoaderFragment implements Messenger messenger = new Messenger(returnHandler); SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance( - messenger, mCurrentPassphrase, R.string.title_change_passphrase); + messenger, R.string.title_change_passphrase); setPassphraseDialog.show(getActivity().getSupportFragmentManager(), "setPassphraseDialog"); } @@ -593,8 +544,11 @@ public class EditKeyFragment extends LoaderFragment implements getActivity().finish(); } - private void saveInDatabase(String passphrase) { - Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel.toString()); + @Override + protected void cryptoOperation(CryptoInputParcel cryptoInput) { + + Log.d(Constants.TAG, "cryptoInput:\n" + cryptoInput); + Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel); KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( getActivity(), @@ -605,6 +559,10 @@ public class EditKeyFragment extends LoaderFragment implements // handle messages by standard KeychainIntentServiceHandler first super.handleMessage(message); + if (handlePendingMessage(message)) { + return; + } + if (message.arg1 == MessageStatus.OKAY.ordinal()) { // get returned data bundle @@ -640,7 +598,7 @@ public class EditKeyFragment extends LoaderFragment implements // fill values for this action Bundle data = new Bundle(); - data.putString(KeychainIntentService.EDIT_KEYRING_PASSPHRASE, passphrase); + data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); data.putParcelable(KeychainIntentService.EDIT_KEYRING_PARCEL, mSaveKeyringParcel); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index f9b8e2ab6..66d1ad5a6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -62,10 +62,9 @@ public abstract class EncryptActivity extends BaseActivity { startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); } - protected void startNfcSign(long keyId, String pin, RequiredInputParcel nfcOps) { + protected void startNfcSign(long keyId, RequiredInputParcel nfcOps) { Intent intent = new Intent(this, NfcOperationActivity.class); - intent.putExtra(NfcOperationActivity.EXTRA_PIN, pin); intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, nfcOps); // TODO respect keyid(?) @@ -148,8 +147,7 @@ public abstract class EncryptActivity extends BaseActivity { pgpResult.getNfcHash(), pgpResult.getNfcAlgo(), input.getSignatureTime()); - startNfcSign(pgpResult.getNfcKeyId(), - pgpResult.getNfcPassphrase(), parcel); + startNfcSign(pgpResult.getNfcKeyId(), parcel); } else { throw new RuntimeException("Unhandled pending result!"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index 6a83c2361..69467daac 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -40,7 +40,6 @@ import java.nio.ByteBuffer; @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) public class NfcOperationActivity extends BaseActivity { - public static final String EXTRA_PIN = "pin"; public static final String EXTRA_REQUIRED_INPUT = "required_input"; public static final String RESULT_DATA = "result_data"; @@ -50,8 +49,6 @@ public class NfcOperationActivity extends BaseActivity { private NfcAdapter mNfcAdapter; private IsoDep mIsoDep; - private String mPin; - RequiredInputParcel mNfcOperations; @Override @@ -70,7 +67,6 @@ public class NfcOperationActivity extends BaseActivity { Bundle data = intent.getExtras(); mNfcOperations = data.getParcelable(EXTRA_REQUIRED_INPUT); - mPin = data.getString(EXTRA_PIN); } @@ -161,14 +157,16 @@ public class NfcOperationActivity extends BaseActivity { return; } + String pin = mNfcOperations.mNfcPin; + // Command APDU for VERIFY command (page 32) String login = "00" // CLA + "20" // INS + "00" // P1 + "82" // P2 (PW1) - + String.format("%02x", mPin.length()) // Lc - + Hex.toHexString(mPin.getBytes()); + + String.format("%02x", pin.length()) // Lc + + Hex.toHexString(pin.getBytes()); if ( ! card(login).equals(accepted)) { // login toast("Wrong PIN!"); setResult(RESULT_CANCELED); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java index b34dc2edc..dc8d8f303 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java @@ -49,7 +49,6 @@ import org.sufficientlysecure.keychain.util.Log; public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener { private static final String ARG_MESSENGER = "messenger"; private static final String ARG_TITLE = "title"; - private static final String ARG_OLD_PASSPHRASE = "old_passphrase"; public static final int MESSAGE_OKAY = 1; @@ -67,12 +66,11 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi * @param messenger to communicate back after setting the passphrase * @return */ - public static SetPassphraseDialogFragment newInstance(Messenger messenger, String oldPassphrase, int title) { + public static SetPassphraseDialogFragment newInstance(Messenger messenger, int title) { SetPassphraseDialogFragment frag = new SetPassphraseDialogFragment(); Bundle args = new Bundle(); args.putInt(ARG_TITLE, title); args.putParcelable(ARG_MESSENGER, messenger); - args.putString(ARG_OLD_PASSPHRASE, oldPassphrase); frag.setArguments(args); @@ -88,7 +86,6 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi int title = getArguments().getInt(ARG_TITLE); mMessenger = getArguments().getParcelable(ARG_MESSENGER); - String oldPassphrase = getArguments().getString(ARG_OLD_PASSPHRASE); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); @@ -102,13 +99,6 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again); mNoPassphraseCheckBox = (CheckBox) view.findViewById(R.id.passphrase_no_passphrase); - - if (TextUtils.isEmpty(oldPassphrase)) { - mNoPassphraseCheckBox.setChecked(true); - mPassphraseEditText.setEnabled(false); - mPassphraseAgainEditText.setEnabled(false); - } - mNoPassphraseCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { -- cgit v1.2.3 From e00ce86de911e5b3f9aa7f5d8f1cb40e310e95e3 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 20 Mar 2015 14:57:38 +0100 Subject: fix more unit tests (syntax) --- .../java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index a5f818734..a42c52e63 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -321,9 +321,10 @@ public class CertifyKeyFragment extends CryptoOperationFragment Bundle data = new Bundle(); { // fill values for this action - CertifyActionsParcel parcel = new CertifyActionsParcel(cryptoInput, mSignMasterKeyId); + CertifyActionsParcel parcel = new CertifyActionsParcel(mSignMasterKeyId); parcel.mCertifyActions.addAll(certifyActions); + data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); data.putParcelable(KeychainIntentService.CERTIFY_PARCEL, parcel); if (mUploadKeyCheckbox.isChecked()) { String keyserver = Preferences.getPreferences(getActivity()).getPreferredKeyserver(); -- cgit v1.2.3 From 93c7eb72fbbf93938043566dfc1707b6714f325b Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 21 Mar 2015 15:16:32 +0100 Subject: more data in RequiredInputParcel, OperationResult notifications - pass both masterkeyid and subkeyid though RequiredInputParcel parcel - fix numeric vales in OperationResult.createNotify() --- .../keychain/ui/NfcOperationActivity.java | 60 +++++++++++++++++----- 1 file changed, 47 insertions(+), 13 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index 69467daac..68eee2513 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -26,6 +26,8 @@ import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; +import org.sufficientlysecure.keychain.util.Preferences; import java.io.IOException; import java.nio.ByteBuffer; @@ -40,6 +42,8 @@ import java.nio.ByteBuffer; @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) public class NfcOperationActivity extends BaseActivity { + public static final int REQUEST_CODE_PASSPHRASE = 1; + public static final String EXTRA_REQUIRED_INPUT = "required_input"; public static final String RESULT_DATA = "result_data"; @@ -49,7 +53,8 @@ public class NfcOperationActivity extends BaseActivity { private NfcAdapter mNfcAdapter; private IsoDep mIsoDep; - RequiredInputParcel mNfcOperations; + RequiredInputParcel mRequiredInput; + private Passphrase mPin; @Override protected void onCreate(Bundle savedInstanceState) { @@ -66,10 +71,40 @@ public class NfcOperationActivity extends BaseActivity { Bundle data = intent.getExtras(); - mNfcOperations = data.getParcelable(EXTRA_REQUIRED_INPUT); + mRequiredInput = data.getParcelable(EXTRA_REQUIRED_INPUT); + + obtainPassphrase(); + + } + + private void obtainPassphrase() { + + Preferences prefs = Preferences.getPreferences(this); + if (prefs.useDefaultYubikeyPin()) { + mPin = new Passphrase("123456"); + return; + } + + Intent intent = new Intent(this, PassphraseDialogActivity.class); + intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, + RequiredInputParcel.createRequiredPassphrase(mRequiredInput)); + startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case REQUEST_CODE_PASSPHRASE: + CryptoInputParcel input = data.getParcelableExtra(PassphraseDialogActivity.RESULT_DATA); + mPin = input.getPassphrase(); + break; + + default: + super.onActivityResult(requestCode, resultCode, data); + } + } + @Override protected void initLayout() { setContentView(R.layout.nfc_activity); @@ -157,7 +192,7 @@ public class NfcOperationActivity extends BaseActivity { return; } - String pin = mNfcOperations.mNfcPin; + byte[] pin = new String(mPin.getCharArray()).getBytes(); // Command APDU for VERIFY command (page 32) String login = @@ -165,8 +200,8 @@ public class NfcOperationActivity extends BaseActivity { + "20" // INS + "00" // P1 + "82" // P2 (PW1) - + String.format("%02x", pin.length()) // Lc - + Hex.toHexString(pin.getBytes()); + + String.format("%02x", pin.length) // Lc + + Hex.toHexString(pin); if ( ! card(login).equals(accepted)) { // login toast("Wrong PIN!"); setResult(RESULT_CANCELED); @@ -174,23 +209,22 @@ public class NfcOperationActivity extends BaseActivity { return; } - CryptoInputParcel resultData = new CryptoInputParcel(mNfcOperations.mSignatureTime); + CryptoInputParcel resultData = new CryptoInputParcel(mRequiredInput.mSignatureTime); - switch (mNfcOperations.mType) { + switch (mRequiredInput.mType) { case NFC_DECRYPT: - - for (int i = 0; i < mNfcOperations.mInputHashes.length; i++) { - byte[] hash = mNfcOperations.mInputHashes[i]; + for (int i = 0; i < mRequiredInput.mInputHashes.length; i++) { + byte[] hash = mRequiredInput.mInputHashes[i]; byte[] decryptedSessionKey = nfcDecryptSessionKey(hash); resultData.addCryptoData(hash, decryptedSessionKey); } break; case NFC_SIGN: - for (int i = 0; i < mNfcOperations.mInputHashes.length; i++) { - byte[] hash = mNfcOperations.mInputHashes[i]; - int algo = mNfcOperations.mSignAlgos[i]; + for (int i = 0; i < mRequiredInput.mInputHashes.length; i++) { + byte[] hash = mRequiredInput.mInputHashes[i]; + int algo = mRequiredInput.mSignAlgos[i]; byte[] signedHash = nfcCalculateSignature(hash, algo); resultData.addCryptoData(hash, signedHash); } -- cgit v1.2.3 From 147003123fffc84b1d658f78d0a888479ce4ff35 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 21 Mar 2015 17:13:31 +0100 Subject: first steps toward yubikey activity - move BaseActivity into new package - extract BaseNfcActivity from NfcOperationsActivity --- .../keychain/ui/BaseActivity.java | 139 ------- .../keychain/ui/CertifyFingerprintActivity.java | 1 + .../keychain/ui/CertifyKeyActivity.java | 2 + .../keychain/ui/CreateKeyActivity.java | 8 +- .../keychain/ui/CreateKeyStartFragment.java | 10 +- .../keychain/ui/CreateKeyYubiFragment.java | 90 +++++ .../keychain/ui/DecryptFilesActivity.java | 2 +- .../keychain/ui/DecryptTextActivity.java | 1 + .../keychain/ui/EditKeyActivity.java | 1 + .../keychain/ui/EncryptActivity.java | 1 + .../keychain/ui/HelpActivity.java | 2 + .../keychain/ui/ImportKeysActivity.java | 1 + .../keychain/ui/LogDisplayActivity.java | 2 + .../keychain/ui/NfcActivity.java | 1 + .../keychain/ui/NfcIntentActivity.java | 1 + .../keychain/ui/NfcOperationActivity.java | 446 +------------------- .../keychain/ui/QrCodeViewActivity.java | 1 + .../keychain/ui/SafeSlingerActivity.java | 1 + .../keychain/ui/SettingsKeyServerActivity.java | 1 + .../keychain/ui/UploadKeyActivity.java | 1 + .../keychain/ui/ViewCertActivity.java | 1 + .../keychain/ui/ViewKeyActivity.java | 1 + .../keychain/ui/ViewKeyAdvActivity.java | 1 + .../keychain/ui/base/BaseActivity.java | 139 +++++++ .../keychain/ui/base/BaseNfcActivity.java | 448 +++++++++++++++++++++ 25 files changed, 721 insertions(+), 581 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java deleted file mode 100644 index 41fa50705..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * - * 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.app.Activity; -import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.support.v7.widget.Toolbar; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; - -/** - * Setups Toolbar - */ -public abstract class BaseActivity extends ActionBarActivity { - protected Toolbar mToolbar; - protected View mStatusBar; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - initLayout(); - initToolbar(); - } - - protected abstract void initLayout(); - - protected void initToolbar() { - mToolbar = (Toolbar) findViewById(R.id.toolbar); - if (mToolbar != null) { - setSupportActionBar(mToolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - } - mStatusBar = findViewById(R.id.status_bar); - } - - protected void setActionBarIcon(int iconRes) { - mToolbar.setNavigationIcon(iconRes); - } - - /** - * Inflate custom design to look like a full screen dialog, as specified in Material Design Guidelines - * see http://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs - */ - protected void setFullScreenDialogDoneClose(int doneText, View.OnClickListener doneOnClickListener, - View.OnClickListener cancelOnClickListener) { - setActionBarIcon(R.drawable.ic_close_white_24dp); - - // Inflate the custom action bar view - final LayoutInflater inflater = (LayoutInflater) getSupportActionBar().getThemedContext() - .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); - final View customActionBarView = inflater.inflate(R.layout.full_screen_dialog, null); - - TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.full_screen_dialog_done_text)); - firstTextView.setText(doneText); - customActionBarView.findViewById(R.id.full_screen_dialog_done).setOnClickListener( - doneOnClickListener); - - getSupportActionBar().setDisplayShowCustomEnabled(true); - getSupportActionBar().setDisplayShowTitleEnabled(true); - getSupportActionBar().setCustomView(customActionBarView, new ActionBar.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, - Gravity.END)); - mToolbar.setNavigationOnClickListener(cancelOnClickListener); - } - - /** - * Close button only - */ - protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener, boolean white) { - if (white) { - setActionBarIcon(R.drawable.ic_close_white_24dp); - } else { - setActionBarIcon(R.drawable.ic_close_black_24dp); - } - getSupportActionBar().setDisplayShowTitleEnabled(true); - mToolbar.setNavigationOnClickListener(cancelOnClickListener); - } - - protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener) { - setFullScreenDialogClose(cancelOnClickListener, true); - } - - /** - * Inflate custom design with two buttons using drawables. - * This does not conform to the Material Design Guidelines, but we deviate here as this is used - * to indicate "Allow access"/"Disallow access" to the API, which must be clearly indicated - */ - protected void setFullScreenDialogTwoButtons(int firstText, int firstDrawableId, View.OnClickListener firstOnClickListener, - int secondText, int secondDrawableId, View.OnClickListener secondOnClickListener) { - - // Inflate the custom action bar view - final LayoutInflater inflater = (LayoutInflater) getSupportActionBar().getThemedContext() - .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); - final View customActionBarView = inflater.inflate( - R.layout.full_screen_dialog_2, null); - - TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); - firstTextView.setText(firstText); - firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); - customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( - firstOnClickListener); - TextView secondTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text)); - secondTextView.setText(secondText); - secondTextView.setCompoundDrawablesWithIntrinsicBounds(secondDrawableId, 0, 0, 0); - customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener( - secondOnClickListener); - - // Show the custom action bar view and hide the normal Home icon and title. - getSupportActionBar().setDisplayShowTitleEnabled(false); - getSupportActionBar().setDisplayShowHomeEnabled(false); - getSupportActionBar().setDisplayHomeAsUpEnabled(false); - getSupportActionBar().setDisplayShowCustomEnabled(true); - getSupportActionBar().setCustomView(customActionBarView, new ActionBar.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java index b7c80c1ed..016ab5f3c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java @@ -23,6 +23,7 @@ import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.util.Log; public class CertifyFingerprintActivity extends BaseActivity { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index 1fb88b182..3845e07cb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.ui; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; + /** * Signs the specified public key with the specified secret master key diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index ab76f693e..4ae901c6c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -17,12 +17,18 @@ package org.sufficientlysecure.keychain.ui; +import android.app.PendingIntent; +import android.content.Intent; +import android.content.IntentFilter; +import android.nfc.NfcAdapter; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; -import android.view.View; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; +import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; import java.util.ArrayList; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java index 180a52a1c..d23d598fa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java @@ -78,7 +78,7 @@ public class CreateKeyStartFragment extends Fragment { mCreateKey = view.findViewById(R.id.create_key_create_key_button); mImportKey = view.findViewById(R.id.create_key_import_button); -// mYubiKey = view.findViewById(R.id.create_key_yubikey_button); + mYubiKey = view.findViewById(R.id.create_key_yubikey_button); mCancel = (TextView) view.findViewById(R.id.create_key_cancel); if (mCreateKeyActivity.mFirstTime) { @@ -95,6 +95,14 @@ public class CreateKeyStartFragment extends Fragment { } }); + mYubiKey.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CreateKeyYubiFragment frag = new CreateKeyYubiFragment(); + mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT); + } + }); + mImportKey.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java new file mode 100644 index 000000000..665c68d65 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * 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.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; +import org.sufficientlysecure.keychain.ui.widget.NameEditText; + + +public class CreateKeyYubiFragment extends Fragment { + + CreateKeyActivity mCreateKeyActivity; + NameEditText mNameEdit; + View mBackButton; + View mNextButton; + + private static boolean isEditTextNotEmpty(Context context, EditText editText) { + boolean output = true; + if (editText.getText().length() == 0) { + editText.setError(context.getString(R.string.create_key_empty)); + editText.requestFocus(); + output = false; + } else { + editText.setError(null); + } + + return output; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.create_yubikey_fragment, container, false); + + mBackButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT); + } + }); + mNextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + nextClicked(); + } + }); + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mCreateKeyActivity = (CreateKeyActivity) getActivity(); + } + + private void nextClicked() { + if (isEditTextNotEmpty(getActivity(), mNameEdit)) { + // save state + mCreateKeyActivity.mName = mNameEdit.getText().toString(); + + CreateKeyEmailFragment frag = CreateKeyEmailFragment.newInstance(); + mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT); + } + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java index 162b10eca..dce2386b5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java @@ -21,12 +21,12 @@ import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.os.PersistableBundle; import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.api.OpenKeychainIntents; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.util.Log; public class DecryptFilesActivity extends BaseActivity { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java index bc2ec014a..728e3ba41 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java @@ -31,6 +31,7 @@ import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.SingletonResult; import org.sufficientlysecure.keychain.pgp.PgpHelper; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 6dc2994cf..b607ba9f4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -23,6 +23,7 @@ import android.os.Bundle; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.util.Log; public class EditKeyActivity extends BaseActivity { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index b87dec8fc..5254af19f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -33,6 +33,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.util.Passphrase; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java index cd6cdf4d6..4aa706f57 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java @@ -26,6 +26,8 @@ import com.astuetz.PagerSlidingTabStrip; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; + public class HelpActivity extends BaseActivity { public static final String EXTRA_SELECTED_TAB = "selected_tab"; 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 9143609ad..9a7c405d0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java index 0de7bb391..df325d31d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java @@ -22,6 +22,8 @@ import android.os.Bundle; import android.view.View; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; + public class LogDisplayActivity extends BaseActivity { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java index 7311f4879..57acf3e93 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java @@ -22,6 +22,7 @@ import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java index 0ccb206d1..a1affbc39 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java @@ -21,6 +21,7 @@ import android.widget.Toast; import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index 68eee2513..549d9ece7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -7,31 +7,19 @@ package org.sufficientlysecure.keychain.ui; import android.annotation.TargetApi; -import android.app.PendingIntent; import android.content.Intent; -import android.content.IntentFilter; -import android.nfc.NfcAdapter; -import android.nfc.Tag; -import android.nfc.tech.IsoDep; import android.os.Build; import android.os.Bundle; import android.view.WindowManager; -import android.widget.Toast; -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; -import org.sufficientlysecure.keychain.util.Iso7816TLV; +import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Passphrase; -import org.sufficientlysecure.keychain.util.Preferences; import java.io.IOException; -import java.nio.ByteBuffer; - /** * This class provides a communication interface to OpenPGP applications on ISO SmartCard compliant @@ -40,21 +28,13 @@ import java.nio.ByteBuffer; * For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf */ @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) -public class NfcOperationActivity extends BaseActivity { - - public static final int REQUEST_CODE_PASSPHRASE = 1; +public class NfcOperationActivity extends BaseNfcActivity { public static final String EXTRA_REQUIRED_INPUT = "required_input"; public static final String RESULT_DATA = "result_data"; - private static final int TIMEOUT = 100000; - - private NfcAdapter mNfcAdapter; - private IsoDep mIsoDep; - RequiredInputParcel mRequiredInput; - private Passphrase mPin; @Override protected void onCreate(Bundle savedInstanceState) { @@ -64,45 +44,12 @@ public class NfcOperationActivity extends BaseActivity { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); Intent intent = getIntent(); - String action = intent.getAction(); - if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { - throw new AssertionError("should not happen: NfcOperationActivity.onCreate is called instead of onNewIntent!"); - } - Bundle data = intent.getExtras(); mRequiredInput = data.getParcelable(EXTRA_REQUIRED_INPUT); - obtainPassphrase(); - - } - - private void obtainPassphrase() { - - Preferences prefs = Preferences.getPreferences(this); - if (prefs.useDefaultYubikeyPin()) { - mPin = new Passphrase("123456"); - return; - } - - Intent intent = new Intent(this, PassphraseDialogActivity.class); - intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, - RequiredInputParcel.createRequiredPassphrase(mRequiredInput)); - startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); - - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CODE_PASSPHRASE: - CryptoInputParcel input = data.getParcelableExtra(PassphraseDialogActivity.RESULT_DATA); - mPin = input.getPassphrase(); - break; - - default: - super.onActivityResult(requestCode, resultCode, data); - } + // obtain passphrase for this subkey + obtainYubikeyPin(RequiredInputParcel.createRequiredPassphrase(mRequiredInput)); } @Override @@ -110,104 +57,8 @@ public class NfcOperationActivity extends BaseActivity { setContentView(R.layout.nfc_activity); } - /** - * Called when the system is about to start resuming a previous activity, - * disables NFC Foreground Dispatch - */ - public void onPause() { - super.onPause(); - Log.d(Constants.TAG, "NfcOperationActivity.onPause"); - - disableNfcForegroundDispatch(); - } - - /** - * Called when the activity will start interacting with the user, - * enables NFC Foreground Dispatch - */ - public void onResume() { - super.onResume(); - Log.d(Constants.TAG, "NfcOperationActivity.onResume"); - - enableNfcForegroundDispatch(); - } - - /** - * This activity is started as a singleTop activity. - * All new NFC Intents which are delivered to this activity are handled here - */ - public void onNewIntent(Intent intent) { - if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { - try { - handleNdefDiscoveredIntent(intent); - } catch (IOException e) { - Log.e(Constants.TAG, "Connection error!", e); - toast("Connection Error: " + e.getMessage()); - setResult(RESULT_CANCELED); - finish(); - } - } - } - - /** Handle NFC communication and return a result. - * - * This method is called by onNewIntent above upon discovery of an NFC tag. - * It handles initialization and login to the application, subsequently - * calls either nfcCalculateSignature() or nfcDecryptSessionKey(), then - * finishes the activity with an appropiate result. - * - * On general communication, see also - * http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_annex-a.aspx - * - * References to pages are generally related to the OpenPGP Application - * on ISO SmartCard Systems specification. - * - */ - private void handleNdefDiscoveredIntent(Intent intent) throws IOException { - - Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); - - // Connect to the detected tag, setting a couple of settings - mIsoDep = IsoDep.get(detectedTag); - mIsoDep.setTimeout(TIMEOUT); // timeout is set to 100 seconds to avoid cancellation during calculation - mIsoDep.connect(); - - // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. - // See specification, page 51 - String accepted = "9000"; - - // Command APDU (page 51) for SELECT FILE command (page 29) - String opening = - "00" // CLA - + "A4" // INS - + "04" // P1 - + "00" // P2 - + "06" // Lc (number of bytes) - + "D27600012401" // Data (6 bytes) - + "00"; // Le - if ( ! card(opening).equals(accepted)) { // activate connection - toast("Opening Error!"); - setResult(RESULT_CANCELED); - finish(); - return; - } - - byte[] pin = new String(mPin.getCharArray()).getBytes(); - - // Command APDU for VERIFY command (page 32) - String login = - "00" // CLA - + "20" // INS - + "00" // P1 - + "82" // P2 (PW1) - + String.format("%02x", pin.length) // Lc - + Hex.toHexString(pin); - if ( ! card(login).equals(accepted)) { // login - toast("Wrong PIN!"); - setResult(RESULT_CANCELED); - finish(); - return; - } + @Override + protected void onNfcPerform() throws IOException { CryptoInputParcel resultData = new CryptoInputParcel(mRequiredInput.mSignatureTime); @@ -233,292 +84,9 @@ public class NfcOperationActivity extends BaseActivity { // give data through for new service call Intent result = new Intent(); - result.putExtra(RESULT_DATA, resultData); + result.putExtra(NfcOperationActivity.RESULT_DATA, resultData); setResult(RESULT_OK, result); finish(); } - - /** - * Gets the user ID - * - * @return the user id as "name " - * @throws java.io.IOException - */ - public String getUserId() throws IOException { - String info = "00CA006500"; - String data = "00CA005E00"; - return getName(card(info)) + " <" + (new String(Hex.decode(getDataField(card(data))))) + ">"; - } - - /** Return the key id from application specific data stored on tag, or null - * if it doesn't exist. - * - * @param idx Index of the key to return the fingerprint from. - * @return The long key id of the requested key, or null if not found. - */ - public static Long nfcGetKeyId(IsoDep isoDep, int idx) throws IOException { - byte[] fp = nfcGetFingerprint(isoDep, idx); - if (fp == null) { - return null; - } - ByteBuffer buf = ByteBuffer.wrap(fp); - // skip first 12 bytes of the fingerprint - buf.position(12); - // the last eight bytes are the key id (big endian, which is default order in ByteBuffer) - return buf.getLong(); - } - - /** Return fingerprints of all keys from application specific data stored - * on tag, or null if data not available. - * - * @return The fingerprints of all subkeys in a contiguous byte array. - */ - public static byte[] nfcGetFingerprints(IsoDep isoDep) throws IOException { - String data = "00CA006E00"; - byte[] buf = isoDep.transceive(Hex.decode(data)); - - Iso7816TLV tlv = Iso7816TLV.readSingle(buf, true); - Log.d(Constants.TAG, "nfc tlv data:\n" + tlv.prettyPrint()); - - Iso7816TLV fptlv = Iso7816TLV.findRecursive(tlv, 0xc5); - if (fptlv == null) { - return null; - } - - return fptlv.mV; - } - - /** Return the fingerprint from application specific data stored on tag, or - * null if it doesn't exist. - * - * @param idx Index of the key to return the fingerprint from. - * @return The fingerprint of the requested key, or null if not found. - */ - public static byte[] nfcGetFingerprint(IsoDep isoDep, int idx) throws IOException { - byte[] data = nfcGetFingerprints(isoDep); - - // return the master key fingerprint - ByteBuffer fpbuf = ByteBuffer.wrap(data); - byte[] fp = new byte[20]; - fpbuf.position(idx*20); - fpbuf.get(fp, 0, 20); - - return fp; - } - - /** - * Calls to calculate the signature and returns the MPI value - * - * @param hash the hash for signing - * @return a big integer representing the MPI for the given hash - * @throws java.io.IOException - */ - public byte[] nfcCalculateSignature(byte[] hash, int hashAlgo) throws IOException { - - // dsi, including Lc - String dsi; - - Log.i(Constants.TAG, "Hash: " + hashAlgo); - switch (hashAlgo) { - case HashAlgorithmTags.SHA1: - if (hash.length != 20) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 10!"); - } - dsi = "23" // Lc - + "3021" // Tag/Length of Sequence, the 0x21 includes all following 33 bytes - + "3009" // Tag/Length of Sequence, the 0x09 are the following header bytes - + "0605" + "2B0E03021A" // OID of SHA1 - + "0500" // TLV coding of ZERO - + "0414" + getHex(hash); // 0x14 are 20 hash bytes - break; - case HashAlgorithmTags.RIPEMD160: - if (hash.length != 20) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 20!"); - } - dsi = "233021300906052B2403020105000414" + getHex(hash); - break; - case HashAlgorithmTags.SHA224: - if (hash.length != 28) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 28!"); - } - dsi = "2F302D300D06096086480165030402040500041C" + getHex(hash); - break; - case HashAlgorithmTags.SHA256: - if (hash.length != 32) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 32!"); - } - dsi = "333031300D060960864801650304020105000420" + getHex(hash); - break; - case HashAlgorithmTags.SHA384: - if (hash.length != 48) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 48!"); - } - dsi = "433041300D060960864801650304020205000430" + getHex(hash); - break; - case HashAlgorithmTags.SHA512: - if (hash.length != 64) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 64!"); - } - dsi = "533051300D060960864801650304020305000440" + getHex(hash); - break; - default: - throw new RuntimeException("Not supported hash algo!"); - } - - // Command APDU for PERFORM SECURITY OPERATION: COMPUTE DIGITAL SIGNATURE (page 37) - String apdu = - "002A9E9A" // CLA, INS, P1, P2 - + dsi // digital signature input - + "00"; // Le - - String response = card(apdu); - - // split up response into signature and status - String status = response.substring(response.length()-4); - String signature = response.substring(0, response.length() - 4); - - // while we are getting 0x61 status codes, retrieve more data - while (status.substring(0, 2).equals("61")) { - Log.d(Constants.TAG, "requesting more data, status " + status); - // Send GET RESPONSE command - response = card("00C00000" + status.substring(2)); - status = response.substring(response.length()-4); - signature += response.substring(0, response.length()-4); - } - - Log.d(Constants.TAG, "final response:" + status); - - if ( ! status.equals("9000")) { - toast("Bad NFC response code: " + status); - return null; - } - - // Make sure the signature we received is actually the expected number of bytes long! - if (signature.length() != 256 && signature.length() != 512) { - toast("Bad signature length! Expected 128 or 256 bytes, got " + signature.length() / 2); - return null; - } - - return Hex.decode(signature); - } - - /** - * Calls to calculate the signature and returns the MPI value - * - * @param encryptedSessionKey the encoded session key - * @return the decoded session key - * @throws java.io.IOException - */ - public byte[] nfcDecryptSessionKey(byte[] encryptedSessionKey) throws IOException { - String firstApdu = "102a8086fe"; - String secondApdu = "002a808603"; - String le = "00"; - - byte[] one = new byte[254]; - // leave out first byte: - System.arraycopy(encryptedSessionKey, 1, one, 0, one.length); - - byte[] two = new byte[encryptedSessionKey.length - 1 - one.length]; - for (int i = 0; i < two.length; i++) { - two[i] = encryptedSessionKey[i + one.length + 1]; - } - - String first = card(firstApdu + getHex(one)); - String second = card(secondApdu + getHex(two) + le); - - String decryptedSessionKey = getDataField(second); - - Log.d(Constants.TAG, "decryptedSessionKey: " + decryptedSessionKey); - - return Hex.decode(decryptedSessionKey); - } - - /** - * Prints a message to the screen - * - * @param text the text which should be contained within the toast - */ - private void toast(String text) { - Toast.makeText(this, text, Toast.LENGTH_LONG).show(); - } - - /** - * Receive new NFC Intents to this activity only by enabling foreground dispatch. - * This can only be done in onResume! - */ - public void enableNfcForegroundDispatch() { - mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - Intent nfcI = new Intent(this, NfcOperationActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); - PendingIntent nfcPendingIntent = PendingIntent.getActivity(this, 0, nfcI, PendingIntent.FLAG_CANCEL_CURRENT); - IntentFilter[] writeTagFilters = new IntentFilter[]{ - new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED) - }; - - // https://code.google.com/p/android/issues/detail?id=62918 - // maybe mNfcAdapter.enableReaderMode(); ? - try { - mNfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null); - } catch (IllegalStateException e) { - Log.i(Constants.TAG, "NfcForegroundDispatch Error!", e); - } - Log.d(Constants.TAG, "NfcForegroundDispatch has been enabled!"); - } - - /** - * Disable foreground dispatch in onPause! - */ - public void disableNfcForegroundDispatch() { - mNfcAdapter.disableForegroundDispatch(this); - Log.d(Constants.TAG, "NfcForegroundDispatch has been disabled!"); - } - - /** - * Gets the name of the user out of the raw card output regarding card holder related data - * - * @param name the raw card holder related data from the card - * @return the name given in this data - */ - public String getName(String name) { - String slength; - int ilength; - name = name.substring(6); - slength = name.substring(0, 2); - ilength = Integer.parseInt(slength, 16) * 2; - name = name.substring(2, ilength + 2); - name = (new String(Hex.decode(name))).replace('<', ' '); - return (name); - } - - /** - * Reduces the raw data from the card by four characters - * - * @param output the raw data from the card - * @return the data field of that data - */ - private String getDataField(String output) { - return output.substring(0, output.length() - 4); - } - - /** - * Communicates with the OpenPgpCard via the APDU - * - * @param hex the hexadecimal APDU - * @return The answer from the card - * @throws java.io.IOException throws an exception if something goes wrong - */ - public String card(String hex) throws IOException { - return getHex(mIsoDep.transceive(Hex.decode(hex))); - } - - /** - * Converts a byte array into an hex string - * - * @param raw the byte array representation - * @return the hexadecimal string representation - */ - public static String getHex(byte[] raw) { - return new String(Hex.encode(raw)); - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java index 43af07bbe..d4858ee5d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java @@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java index 863aef65f..a41416a47 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java @@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ParcelableFileCache; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java index 080dc2495..9f2e46b38 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java @@ -27,6 +27,7 @@ import android.view.ViewGroup; import android.widget.TextView; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.widget.Editor; import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; import org.sufficientlysecure.keychain.ui.widget.KeyServerEditor; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java index 4fb2074a5..ad13e390d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -37,6 +37,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java index a80503591..8d876ba69 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 484956e6a..fc30eafcc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -66,6 +66,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus; import org.sufficientlysecure.keychain.service.PassphraseCacheService; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java index f17d6e0fd..9e8a12c8a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java @@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.util.ExportHelper; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java new file mode 100644 index 000000000..07d2ef8c0 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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.base; + +import android.app.Activity; +import android.os.Bundle; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.Toolbar; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.R; + +/** + * Setups Toolbar + */ +public abstract class BaseActivity extends ActionBarActivity { + protected Toolbar mToolbar; + protected View mStatusBar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initLayout(); + initToolbar(); + } + + protected abstract void initLayout(); + + protected void initToolbar() { + mToolbar = (Toolbar) findViewById(R.id.toolbar); + if (mToolbar != null) { + setSupportActionBar(mToolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + mStatusBar = findViewById(R.id.status_bar); + } + + protected void setActionBarIcon(int iconRes) { + mToolbar.setNavigationIcon(iconRes); + } + + /** + * Inflate custom design to look like a full screen dialog, as specified in Material Design Guidelines + * see http://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs + */ + public void setFullScreenDialogDoneClose(int doneText, View.OnClickListener doneOnClickListener, + View.OnClickListener cancelOnClickListener) { + setActionBarIcon(R.drawable.ic_close_white_24dp); + + // Inflate the custom action bar view + final LayoutInflater inflater = (LayoutInflater) getSupportActionBar().getThemedContext() + .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); + final View customActionBarView = inflater.inflate(R.layout.full_screen_dialog, null); + + TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.full_screen_dialog_done_text)); + firstTextView.setText(doneText); + customActionBarView.findViewById(R.id.full_screen_dialog_done).setOnClickListener( + doneOnClickListener); + + getSupportActionBar().setDisplayShowCustomEnabled(true); + getSupportActionBar().setDisplayShowTitleEnabled(true); + getSupportActionBar().setCustomView(customActionBarView, new ActionBar.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, + Gravity.END)); + mToolbar.setNavigationOnClickListener(cancelOnClickListener); + } + + /** + * Close button only + */ + protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener, boolean white) { + if (white) { + setActionBarIcon(R.drawable.ic_close_white_24dp); + } else { + setActionBarIcon(R.drawable.ic_close_black_24dp); + } + getSupportActionBar().setDisplayShowTitleEnabled(true); + mToolbar.setNavigationOnClickListener(cancelOnClickListener); + } + + protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener) { + setFullScreenDialogClose(cancelOnClickListener, true); + } + + /** + * Inflate custom design with two buttons using drawables. + * This does not conform to the Material Design Guidelines, but we deviate here as this is used + * to indicate "Allow access"/"Disallow access" to the API, which must be clearly indicated + */ + protected void setFullScreenDialogTwoButtons(int firstText, int firstDrawableId, View.OnClickListener firstOnClickListener, + int secondText, int secondDrawableId, View.OnClickListener secondOnClickListener) { + + // Inflate the custom action bar view + final LayoutInflater inflater = (LayoutInflater) getSupportActionBar().getThemedContext() + .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); + final View customActionBarView = inflater.inflate( + R.layout.full_screen_dialog_2, null); + + TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); + firstTextView.setText(firstText); + firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); + customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( + firstOnClickListener); + TextView secondTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text)); + secondTextView.setText(secondText); + secondTextView.setCompoundDrawablesWithIntrinsicBounds(secondDrawableId, 0, 0, 0); + customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener( + secondOnClickListener); + + // Show the custom action bar view and hide the normal Home icon and title. + getSupportActionBar().setDisplayShowTitleEnabled(false); + getSupportActionBar().setDisplayShowHomeEnabled(false); + getSupportActionBar().setDisplayHomeAsUpEnabled(false); + getSupportActionBar().setDisplayShowCustomEnabled(true); + getSupportActionBar().setCustomView(customActionBarView, new ActionBar.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java new file mode 100644 index 000000000..0a7b7611b --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -0,0 +1,448 @@ +package org.sufficientlysecure.keychain.ui.base; + + +import java.io.IOException; +import java.nio.ByteBuffer; + +import android.app.PendingIntent; +import android.content.Intent; +import android.content.IntentFilter; +import android.nfc.NfcAdapter; +import android.nfc.Tag; +import android.nfc.tech.IsoDep; +import android.os.Bundle; +import android.widget.Toast; + +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.util.encoders.Hex; +import org.sufficientlysecure.keychain.Constants; +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.PassphraseDialogActivity; +import org.sufficientlysecure.keychain.util.Iso7816TLV; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; +import org.sufficientlysecure.keychain.util.Preferences; + + +public abstract class BaseNfcActivity extends BaseActivity { + + public static final int REQUEST_CODE_PASSPHRASE = 1; + + protected Passphrase mPin; + private NfcAdapter mNfcAdapter; + private IsoDep mIsoDep; + + private static final int TIMEOUT = 100000; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + String action = intent.getAction(); + if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { + throw new AssertionError("should not happen: NfcOperationActivity.onCreate is called instead of onNewIntent!"); + } + + } + + /** + * This activity is started as a singleTop activity. + * All new NFC Intents which are delivered to this activity are handled here + */ + @Override + public void onNewIntent(Intent intent) { + if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { + try { + handleNdefDiscoveredIntent(intent); + } catch (IOException e) { + Log.e(Constants.TAG, "Connection error!", e); + toast("Connection Error: " + e.getMessage()); + setResult(RESULT_CANCELED); + finish(); + } + } + } + + /** + * Called when the system is about to start resuming a previous activity, + * disables NFC Foreground Dispatch + */ + public void onPause() { + super.onPause(); + Log.d(Constants.TAG, "NfcOperationActivity.onPause"); + + disableNfcForegroundDispatch(); + } + + /** + * Called when the activity will start interacting with the user, + * enables NFC Foreground Dispatch + */ + public void onResume() { + super.onResume(); + Log.d(Constants.TAG, "NfcOperationActivity.onResume"); + + enableNfcForegroundDispatch(); + } + + protected void obtainYubikeyPin(RequiredInputParcel requiredInput) { + + Preferences prefs = Preferences.getPreferences(this); + if (prefs.useDefaultYubikeyPin()) { + mPin = new Passphrase("123456"); + return; + } + + Intent intent = new Intent(this, PassphraseDialogActivity.class); + intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, + RequiredInputParcel.createRequiredPassphrase(requiredInput)); + startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); + + } + + protected void setYubikeyPin(Passphrase pin) { + mPin = pin; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case REQUEST_CODE_PASSPHRASE: + CryptoInputParcel input = data.getParcelableExtra(PassphraseDialogActivity.RESULT_DATA); + mPin = input.getPassphrase(); + break; + + default: + super.onActivityResult(requestCode, resultCode, data); + } + } + + /** Handle NFC communication and return a result. + * + * This method is called by onNewIntent above upon discovery of an NFC tag. + * It handles initialization and login to the application, subsequently + * calls either nfcCalculateSignature() or nfcDecryptSessionKey(), then + * finishes the activity with an appropiate result. + * + * On general communication, see also + * http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_annex-a.aspx + * + * References to pages are generally related to the OpenPGP Application + * on ISO SmartCard Systems specification. + * + */ + protected void handleNdefDiscoveredIntent(Intent intent) throws IOException { + + Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + + // Connect to the detected tag, setting a couple of settings + mIsoDep = IsoDep.get(detectedTag); + mIsoDep.setTimeout(TIMEOUT); // timeout is set to 100 seconds to avoid cancellation during calculation + mIsoDep.connect(); + + // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. + // See specification, page 51 + String accepted = "9000"; + + // Command APDU (page 51) for SELECT FILE command (page 29) + String opening = + "00" // CLA + + "A4" // INS + + "04" // P1 + + "00" // P2 + + "06" // Lc (number of bytes) + + "D27600012401" // Data (6 bytes) + + "00"; // Le + if ( ! nfcCommunicate(opening).equals(accepted)) { // activate connection + toast("Opening Error!"); + setResult(RESULT_CANCELED); + finish(); + return; + } + + if (mPin != null) { + + byte[] pin = new String(mPin.getCharArray()).getBytes(); + + // Command APDU for VERIFY command (page 32) + String login = + "00" // CLA + + "20" // INS + + "00" // P1 + + "82" // P2 (PW1) + + String.format("%02x", pin.length) // Lc + + Hex.toHexString(pin); + if (!nfcCommunicate(login).equals(accepted)) { // login + toast("Wrong PIN!"); + setResult(RESULT_CANCELED); + finish(); + return; + } + + } + + onNfcPerform(); + + mIsoDep.close(); + mIsoDep = null; + + } + + protected abstract void onNfcPerform() throws IOException; + + /** Return the key id from application specific data stored on tag, or null + * if it doesn't exist. + * + * @param idx Index of the key to return the fingerprint from. + * @return The long key id of the requested key, or null if not found. + */ + public Long nfcGetKeyId(int idx) throws IOException { + byte[] fp = nfcGetFingerprint(idx); + if (fp == null) { + return null; + } + ByteBuffer buf = ByteBuffer.wrap(fp); + // skip first 12 bytes of the fingerprint + buf.position(12); + // the last eight bytes are the key id (big endian, which is default order in ByteBuffer) + return buf.getLong(); + } + + /** Return fingerprints of all keys from application specific data stored + * on tag, or null if data not available. + * + * @return The fingerprints of all subkeys in a contiguous byte array. + */ + public byte[] nfcGetFingerprints() throws IOException { + String data = "00CA006E00"; + byte[] buf = mIsoDep.transceive(Hex.decode(data)); + + Iso7816TLV tlv = Iso7816TLV.readSingle(buf, true); + Log.d(Constants.TAG, "nfc tlv data:\n" + tlv.prettyPrint()); + + Iso7816TLV fptlv = Iso7816TLV.findRecursive(tlv, 0xc5); + if (fptlv == null) { + return null; + } + + return fptlv.mV; + } + + /** Return the fingerprint from application specific data stored on tag, or + * null if it doesn't exist. + * + * @param idx Index of the key to return the fingerprint from. + * @return The fingerprint of the requested key, or null if not found. + */ + public byte[] nfcGetFingerprint(int idx) throws IOException { + byte[] data = nfcGetFingerprints(); + + // return the master key fingerprint + ByteBuffer fpbuf = ByteBuffer.wrap(data); + byte[] fp = new byte[20]; + fpbuf.position(idx*20); + fpbuf.get(fp, 0, 20); + + return fp; + } + + + public String nfcGetUserId() throws IOException { + String info = "00CA006500"; + String data = "00CA005E00"; + return nfcGetHolderName(nfcCommunicate(info)) + " <" + (new String(Hex.decode(nfcGetDataField( + nfcCommunicate(data))))) + ">"; + } + + /** + * Calls to calculate the signature and returns the MPI value + * + * @param hash the hash for signing + * @return a big integer representing the MPI for the given hash + */ + public byte[] nfcCalculateSignature(byte[] hash, int hashAlgo) throws IOException { + + // dsi, including Lc + String dsi; + + Log.i(Constants.TAG, "Hash: " + hashAlgo); + switch (hashAlgo) { + case HashAlgorithmTags.SHA1: + if (hash.length != 20) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 10!"); + } + dsi = "23" // Lc + + "3021" // Tag/Length of Sequence, the 0x21 includes all following 33 bytes + + "3009" // Tag/Length of Sequence, the 0x09 are the following header bytes + + "0605" + "2B0E03021A" // OID of SHA1 + + "0500" // TLV coding of ZERO + + "0414" + getHex(hash); // 0x14 are 20 hash bytes + break; + case HashAlgorithmTags.RIPEMD160: + if (hash.length != 20) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 20!"); + } + dsi = "233021300906052B2403020105000414" + getHex(hash); + break; + case HashAlgorithmTags.SHA224: + if (hash.length != 28) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 28!"); + } + dsi = "2F302D300D06096086480165030402040500041C" + getHex(hash); + break; + case HashAlgorithmTags.SHA256: + if (hash.length != 32) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 32!"); + } + dsi = "333031300D060960864801650304020105000420" + getHex(hash); + break; + case HashAlgorithmTags.SHA384: + if (hash.length != 48) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 48!"); + } + dsi = "433041300D060960864801650304020205000430" + getHex(hash); + break; + case HashAlgorithmTags.SHA512: + if (hash.length != 64) { + throw new RuntimeException("Bad hash length (" + hash.length + ", expected 64!"); + } + dsi = "533051300D060960864801650304020305000440" + getHex(hash); + break; + default: + throw new RuntimeException("Not supported hash algo!"); + } + + // Command APDU for PERFORM SECURITY OPERATION: COMPUTE DIGITAL SIGNATURE (page 37) + String apdu = + "002A9E9A" // CLA, INS, P1, P2 + + dsi // digital signature input + + "00"; // Le + + String response = nfcCommunicate(apdu); + + // split up response into signature and status + String status = response.substring(response.length()-4); + String signature = response.substring(0, response.length() - 4); + + // while we are getting 0x61 status codes, retrieve more data + while (status.substring(0, 2).equals("61")) { + Log.d(Constants.TAG, "requesting more data, status " + status); + // Send GET RESPONSE command + response = nfcCommunicate("00C00000" + status.substring(2)); + status = response.substring(response.length()-4); + signature += response.substring(0, response.length()-4); + } + + Log.d(Constants.TAG, "final response:" + status); + + if ( ! "9000".equals(status)) { + toast("Bad NFC response code: " + status); + return null; + } + + // Make sure the signature we received is actually the expected number of bytes long! + if (signature.length() != 256 && signature.length() != 512) { + toast("Bad signature length! Expected 128 or 256 bytes, got " + signature.length() / 2); + return null; + } + + return Hex.decode(signature); + } + + /** + * Calls to calculate the signature and returns the MPI value + * + * @param encryptedSessionKey the encoded session key + * @return the decoded session key + */ + public byte[] nfcDecryptSessionKey(byte[] encryptedSessionKey) throws IOException { + String firstApdu = "102a8086fe"; + String secondApdu = "002a808603"; + String le = "00"; + + byte[] one = new byte[254]; + // leave out first byte: + System.arraycopy(encryptedSessionKey, 1, one, 0, one.length); + + byte[] two = new byte[encryptedSessionKey.length - 1 - one.length]; + for (int i = 0; i < two.length; i++) { + two[i] = encryptedSessionKey[i + one.length + 1]; + } + + String first = nfcCommunicate(firstApdu + getHex(one)); + String second = nfcCommunicate(secondApdu + getHex(two) + le); + + String decryptedSessionKey = nfcGetDataField(second); + + Log.d(Constants.TAG, "decryptedSessionKey: " + decryptedSessionKey); + + return Hex.decode(decryptedSessionKey); + } + + /** + * Prints a message to the screen + * + * @param text the text which should be contained within the toast + */ + protected void toast(String text) { + Toast.makeText(this, text, Toast.LENGTH_LONG).show(); + } + + /** + * Receive new NFC Intents to this activity only by enabling foreground dispatch. + * This can only be done in onResume! + */ + public void enableNfcForegroundDispatch() { + mNfcAdapter = NfcAdapter.getDefaultAdapter(this); + Intent nfcI = new Intent(this, NfcOperationActivity.class) + .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + PendingIntent nfcPendingIntent = PendingIntent.getActivity(this, 0, nfcI, PendingIntent.FLAG_CANCEL_CURRENT); + IntentFilter[] writeTagFilters = new IntentFilter[]{ + new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED) + }; + + // https://code.google.com/p/android/issues/detail?id=62918 + // maybe mNfcAdapter.enableReaderMode(); ? + try { + mNfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null); + } catch (IllegalStateException e) { + Log.i(Constants.TAG, "NfcForegroundDispatch Error!", e); + } + Log.d(Constants.TAG, "NfcForegroundDispatch has been enabled!"); + } + + /** + * Disable foreground dispatch in onPause! + */ + public void disableNfcForegroundDispatch() { + mNfcAdapter.disableForegroundDispatch(this); + Log.d(Constants.TAG, "NfcForegroundDispatch has been disabled!"); + } + + public String nfcGetHolderName(String name) { + String slength; + int ilength; + name = name.substring(6); + slength = name.substring(0, 2); + ilength = Integer.parseInt(slength, 16) * 2; + name = name.substring(2, ilength + 2); + name = (new String(Hex.decode(name))).replace('<', ' '); + return (name); + } + + private String nfcGetDataField(String output) { + return output.substring(0, output.length() - 4); + } + + public String nfcCommunicate(String apdu) throws IOException { + return getHex(mIsoDep.transceive(Hex.decode(apdu))); + } + + public static String getHex(byte[] raw) { + return new String(Hex.encode(raw)); + } + +} -- cgit v1.2.3 From 1ad3635d139ea5033b06e5cdd87a7b2eab5f2e75 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 21 Mar 2015 19:52:10 +0100 Subject: work on ad-hoc yubikey import support --- .../keychain/ui/CreateKeyActivity.java | 22 +- .../keychain/ui/CreateKeyYubiFragment.java | 259 ++++++++++++++++++++- .../keychain/ui/base/BaseNfcActivity.java | 7 +- 3 files changed, 270 insertions(+), 18 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 4ae901c6c..9919e2aab 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -17,23 +17,18 @@ package org.sufficientlysecure.keychain.ui; -import android.app.PendingIntent; -import android.content.Intent; -import android.content.IntentFilter; -import android.nfc.NfcAdapter; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.base.BaseActivity; -import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.util.Passphrase; +import java.io.IOException; import java.util.ArrayList; -public class CreateKeyActivity extends BaseActivity { +public class CreateKeyActivity extends BaseNfcActivity { public static final String EXTRA_NAME = "name"; public static final String EXTRA_EMAIL = "email"; @@ -85,6 +80,13 @@ public class CreateKeyActivity extends BaseActivity { } } + @Override + protected void onNfcPerform() throws IOException { + if (mCurrentFragment instanceof NfcListenerFragment) { + ((NfcListenerFragment) mCurrentFragment).onNfcPerform(); + } + } + @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -135,4 +137,8 @@ public class CreateKeyActivity extends BaseActivity { getSupportFragmentManager().executePendingTransactions(); } + interface NfcListenerFragment { + public void onNfcPerform() throws IOException; + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java index 665c68d65..483a5f4e5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java @@ -17,26 +17,77 @@ package org.sufficientlysecure.keychain.ui; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; + import android.app.Activity; +import android.app.ProgressDialog; import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; +import android.widget.TextView; +import android.widget.ViewAnimator; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentService.IOType; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; +import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment; +import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.widget.NameEditText; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; -public class CreateKeyYubiFragment extends Fragment { +public class CreateKeyYubiFragment extends Fragment implements NfcListenerFragment, + LoaderManager.LoaderCallbacks { CreateKeyActivity mCreateKeyActivity; NameEditText mNameEdit; View mBackButton; View mNextButton; + private TextView mUnknownFingerprint; + + public static final String ARGS_MASTER_KEY_ID = "master_key_id"; + private byte[] mScannedFingerprint; + private long mScannedMasterKeyId; + private ViewAnimator mAnimator; + private TextView mFingerprint; + private TextView mUserId; + + private YubiImportState mState = YubiImportState.SCAN; + + enum YubiImportState { + SCAN, // waiting for scan + UNKNOWN, // scanned unknown key (ready to import) + BAD_FINGERPRINT, // scanned key, bad fingerprint + IMPORTED, // imported key (ready to promote) + } private static boolean isEditTextNotEmpty(Context context, EditText editText) { boolean output = true; @@ -55,6 +106,16 @@ public class CreateKeyYubiFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.create_yubikey_fragment, container, false); + mAnimator = (ViewAnimator) view.findViewById(R.id.create_yubikey_animator); + + mUnknownFingerprint = (TextView) view.findViewById(R.id.create_yubikey_unknown_fp); + + mFingerprint = (TextView) view.findViewById(R.id.create_yubikey_fingerprint); + mUserId = (TextView) view.findViewById(R.id.create_yubikey_user_id); + + mBackButton = view.findViewById(R.id.create_key_back_button); + mNextButton = view.findViewById(R.id.create_key_next_button); + mBackButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -77,14 +138,200 @@ public class CreateKeyYubiFragment extends Fragment { mCreateKeyActivity = (CreateKeyActivity) getActivity(); } + @Override + public void onNfcPerform() throws IOException { + + mScannedFingerprint = mCreateKeyActivity.nfcGetFingerprint(0); + mScannedMasterKeyId = getKeyIdFromFingerprint(mScannedFingerprint); + + getLoaderManager().initLoader(0, null, this); + + } + + // These are the rows that we will retrieve. + static final String[] UNIFIED_PROJECTION = new String[]{ + KeychainContract.KeyRings._ID, + KeychainContract.KeyRings.MASTER_KEY_ID, + KeychainContract.KeyRings.USER_ID, + KeychainContract.KeyRings.IS_REVOKED, + KeychainContract.KeyRings.IS_EXPIRED, + KeychainContract.KeyRings.HAS_ANY_SECRET, + KeychainContract.KeyRings.FINGERPRINT, + }; + + static final int INDEX_MASTER_KEY_ID = 1; + static final int INDEX_USER_ID = 2; + static final int INDEX_IS_REVOKED = 3; + static final int INDEX_IS_EXPIRED = 4; + static final int INDEX_HAS_ANY_SECRET = 5; + static final int INDEX_FINGERPRINT = 6; + + @Override + public Loader onCreateLoader(int id, Bundle args) { + Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri( + KeyRings.buildUnifiedKeyRingUri(mScannedMasterKeyId) + ); + return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + if (data.moveToFirst()) { + + byte[] fingerprint = data.getBlob(INDEX_FINGERPRINT); + if (!Arrays.equals(fingerprint, mScannedFingerprint)) { + mState = YubiImportState.BAD_FINGERPRINT; + Notify.create(getActivity(), "Fingerprint mismatch!", Style.ERROR); + return; + } + + showKey(data); + + } else { + showUnknownKey(); + } + } + + public void showUnknownKey() { + String fp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); + mUnknownFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fp)); + + mAnimator.setDisplayedChild(1); + mState = YubiImportState.UNKNOWN; + } + + public void showKey(Cursor data) { + String userId = data.getString(INDEX_USER_ID); + boolean hasSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; + + String fp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); + mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fp)); + + mUserId.setText(userId); + + mAnimator.setDisplayedChild(2); + mState = YubiImportState.IMPORTED; + } + + private void nextClicked() { - if (isEditTextNotEmpty(getActivity(), mNameEdit)) { - // save state - mCreateKeyActivity.mName = mNameEdit.getText().toString(); - CreateKeyEmailFragment frag = CreateKeyEmailFragment.newInstance(); - mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT); + switch (mState) { + case UNKNOWN: + importKey(); + break; + case IMPORTED: + promoteKey(); + break; } + + } + + public void promoteKey() { + + // Message is received after decrypting is done in KeychainIntentService + KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity()) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == MessageStatus.OKAY.ordinal()) { + // get returned data bundle + Bundle returnData = message.getData(); + + PromoteKeyResult result = + returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); + + result.createNotify(getActivity()).show(); + } + + } + }; + + // Send all information needed to service to decrypt in other thread + Intent intent = new Intent(getActivity(), KeychainIntentService.class); + + // fill values for this action + + intent.setAction(KeychainIntentService.ACTION_PROMOTE_KEYRING); + + Bundle data = new Bundle(); + data.putLong(KeychainIntentService.PROMOTE_MASTER_KEY_ID, mScannedMasterKeyId); + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(saveHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // start service with intent + getActivity().startService(intent); + + } + + public void importKey() { + + // Message is received after decrypting is done in KeychainIntentService + KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity()) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == MessageStatus.OKAY.ordinal()) { + // get returned data bundle + Bundle returnData = message.getData(); + + ImportKeyResult result = + returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); + + result.createNotify(getActivity()).show(); + } + + } + }; + + // Send all information needed to service to decrypt in other thread + Intent intent = new Intent(getActivity(), KeychainIntentService.class); + + // fill values for this action + Bundle data = new Bundle(); + + intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING); + + String hexFp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); + ArrayList keyList = new ArrayList<>(); + keyList.add(new ParcelableKeyRing(hexFp, null, null)); + data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, keyList); + + { + Preferences prefs = Preferences.getPreferences(getActivity()); + Preferences.CloudSearchPrefs cloudPrefs = + new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver()); + data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver); + } + + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(saveHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // start service with intent + getActivity().startService(intent); + + } + + + @Override + public void onLoaderReset(Loader loader) { + + } + + static long getKeyIdFromFingerprint(byte[] fingerprint) { + ByteBuffer buf = ByteBuffer.wrap(fingerprint); + // skip first 12 bytes of the fingerprint + buf.position(12); + // the last eight bytes are the key id (big endian, which is default order in ByteBuffer) + return buf.getLong(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index 0a7b7611b..ca1d79155 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -18,7 +18,6 @@ import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; 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.PassphraseDialogActivity; import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; @@ -72,7 +71,7 @@ public abstract class BaseNfcActivity extends BaseActivity { */ public void onPause() { super.onPause(); - Log.d(Constants.TAG, "NfcOperationActivity.onPause"); + Log.d(Constants.TAG, "BaseNfcActivity.onPause"); disableNfcForegroundDispatch(); } @@ -83,7 +82,7 @@ public abstract class BaseNfcActivity extends BaseActivity { */ public void onResume() { super.onResume(); - Log.d(Constants.TAG, "NfcOperationActivity.onResume"); + Log.d(Constants.TAG, "BaseNfcActivity.onResume"); enableNfcForegroundDispatch(); } @@ -397,7 +396,7 @@ public abstract class BaseNfcActivity extends BaseActivity { */ public void enableNfcForegroundDispatch() { mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - Intent nfcI = new Intent(this, NfcOperationActivity.class) + Intent nfcI = new Intent(this, getClass()) .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); PendingIntent nfcPendingIntent = PendingIntent.getActivity(this, 0, nfcI, PendingIntent.FLAG_CANCEL_CURRENT); IntentFilter[] writeTagFilters = new IntentFilter[]{ -- cgit v1.2.3 From 04c7639a5a9b4f85122b7d5f299ba09131ce3036 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 21 Mar 2015 22:18:58 +0100 Subject: split up wait/action yubikey fragments --- .../keychain/ui/CreateKeyActivity.java | 6 ++ .../keychain/ui/CreateKeyStartFragment.java | 2 +- .../keychain/ui/CreateKeyYubiFragment.java | 105 +++++++++------------ .../keychain/ui/CreateKeyYubiWaitFragment.java | 88 +++++++++++++++++ 4 files changed, 137 insertions(+), 64 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiWaitFragment.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 9919e2aab..5c2fcde82 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -84,7 +84,13 @@ public class CreateKeyActivity extends BaseNfcActivity { protected void onNfcPerform() throws IOException { if (mCurrentFragment instanceof NfcListenerFragment) { ((NfcListenerFragment) mCurrentFragment).onNfcPerform(); + return; } + + byte[] scannedFingerprint = nfcGetFingerprint(0); + Fragment frag = CreateKeyYubiFragment.createInstance(scannedFingerprint); + loadFragment(frag, FragAction.TO_RIGHT); + } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java index d23d598fa..3f56949f5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyStartFragment.java @@ -98,7 +98,7 @@ public class CreateKeyStartFragment extends Fragment { mYubiKey.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - CreateKeyYubiFragment frag = new CreateKeyYubiFragment(); + CreateKeyYubiWaitFragment frag = new CreateKeyYubiWaitFragment(); mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT); } }); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java index 483a5f4e5..63549c3d6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java @@ -23,8 +23,6 @@ import java.util.ArrayList; import java.util.Arrays; import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; @@ -38,11 +36,9 @@ import android.support.v4.content.Loader; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.EditText; import android.widget.TextView; import android.widget.ViewAnimator; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; @@ -51,57 +47,59 @@ import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentService.IOType; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment; -import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.widget.NameEditText; -import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; -public class CreateKeyYubiFragment extends Fragment implements NfcListenerFragment, - LoaderManager.LoaderCallbacks { +public class CreateKeyYubiFragment extends Fragment + implements LoaderManager.LoaderCallbacks { + + private static final String ARG_FINGERPRINT = "fingerprint"; CreateKeyActivity mCreateKeyActivity; - NameEditText mNameEdit; - View mBackButton; - View mNextButton; - private TextView mUnknownFingerprint; - public static final String ARGS_MASTER_KEY_ID = "master_key_id"; private byte[] mScannedFingerprint; private long mScannedMasterKeyId; + private ViewAnimator mAnimator; + private TextView mUnknownFingerprint; private TextView mFingerprint; private TextView mUserId; - private YubiImportState mState = YubiImportState.SCAN; + private YubiImportState mState; + + public static Fragment createInstance(byte[] scannedFingerprint) { + Bundle args = new Bundle(); + args.putByteArray(ARG_FINGERPRINT, scannedFingerprint); + + CreateKeyYubiFragment frag = new CreateKeyYubiFragment(); + frag.setArguments(args); + + return frag; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mScannedFingerprint = getArguments().getByteArray(ARG_FINGERPRINT); + mScannedMasterKeyId = getKeyIdFromFingerprint(mScannedFingerprint); + + getLoaderManager().initLoader(0, null, this); + } enum YubiImportState { - SCAN, // waiting for scan UNKNOWN, // scanned unknown key (ready to import) BAD_FINGERPRINT, // scanned key, bad fingerprint IMPORTED, // imported key (ready to promote) } - private static boolean isEditTextNotEmpty(Context context, EditText editText) { - boolean output = true; - if (editText.getText().length() == 0) { - editText.setError(context.getString(R.string.create_key_empty)); - editText.requestFocus(); - output = false; - } else { - editText.setError(null); - } - - return output; - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.create_yubikey_fragment, container, false); @@ -113,8 +111,8 @@ public class CreateKeyYubiFragment extends Fragment implements NfcListenerFragme mFingerprint = (TextView) view.findViewById(R.id.create_yubikey_fingerprint); mUserId = (TextView) view.findViewById(R.id.create_yubikey_user_id); - mBackButton = view.findViewById(R.id.create_key_back_button); - mNextButton = view.findViewById(R.id.create_key_next_button); + View mBackButton = view.findViewById(R.id.create_key_back_button); + View mNextButton = view.findViewById(R.id.create_key_next_button); mBackButton.setOnClickListener(new View.OnClickListener() { @Override @@ -138,16 +136,6 @@ public class CreateKeyYubiFragment extends Fragment implements NfcListenerFragme mCreateKeyActivity = (CreateKeyActivity) getActivity(); } - @Override - public void onNfcPerform() throws IOException { - - mScannedFingerprint = mCreateKeyActivity.nfcGetFingerprint(0); - mScannedMasterKeyId = getKeyIdFromFingerprint(mScannedFingerprint); - - getLoaderManager().initLoader(0, null, this); - - } - // These are the rows that we will retrieve. static final String[] UNIFIED_PROJECTION = new String[]{ KeychainContract.KeyRings._ID, @@ -185,35 +173,26 @@ public class CreateKeyYubiFragment extends Fragment implements NfcListenerFragme return; } - showKey(data); + String userId = data.getString(INDEX_USER_ID); + boolean hasSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; - } else { - showUnknownKey(); - } - } + String fp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); + mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fp)); - public void showUnknownKey() { - String fp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); - mUnknownFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fp)); - - mAnimator.setDisplayedChild(1); - mState = YubiImportState.UNKNOWN; - } + mUserId.setText(userId); - public void showKey(Cursor data) { - String userId = data.getString(INDEX_USER_ID); - boolean hasSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; + mAnimator.setDisplayedChild(2); + mState = YubiImportState.IMPORTED; - String fp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); - mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fp)); - - mUserId.setText(userId); + } else { + String fp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); + mUnknownFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fp)); - mAnimator.setDisplayedChild(2); - mState = YubiImportState.IMPORTED; + mAnimator.setDisplayedChild(1); + mState = YubiImportState.UNKNOWN; + } } - private void nextClicked() { switch (mState) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiWaitFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiWaitFragment.java new file mode 100644 index 000000000..c338a0f1f --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiWaitFragment.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * 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 java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.ViewAnimator; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; +import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; +import org.sufficientlysecure.keychain.ui.widget.NameEditText; +import org.sufficientlysecure.keychain.util.Preferences; + + +public class CreateKeyYubiWaitFragment extends Fragment { + + CreateKeyActivity mCreateKeyActivity; + View mBackButton; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.create_yubikey_wait_fragment, container, false); + + mBackButton = view.findViewById(R.id.create_key_back_button); + + mBackButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT); + } + }); + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mCreateKeyActivity = (CreateKeyActivity) getActivity(); + } + +} -- cgit v1.2.3 From a7c52a1c9f8bca83b2981347a0eceeec68a92790 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 22 Mar 2015 02:36:10 +0100 Subject: move yubikey import into viewkeyfragment --- .../keychain/ui/CreateKeyActivity.java | 34 ++++- .../keychain/ui/CreateKeyYubiFragment.java | 149 +-------------------- .../keychain/ui/ViewKeyActivity.java | 83 +++++++++++- .../keychain/ui/ViewKeyYubikeyFragment.java | 129 ++++++++++++++++++ .../keychain/ui/base/BaseNfcActivity.java | 11 +- .../keychain/ui/util/KeyFormattingUtils.java | 11 +- 6 files changed, 259 insertions(+), 158 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 5c2fcde82..b73d6f545 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -17,12 +17,21 @@ package org.sufficientlysecure.keychain.ui; +import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.Passphrase; import java.io.IOException; @@ -87,9 +96,28 @@ public class CreateKeyActivity extends BaseNfcActivity { return; } - byte[] scannedFingerprint = nfcGetFingerprint(0); - Fragment frag = CreateKeyYubiFragment.createInstance(scannedFingerprint); - loadFragment(frag, FragAction.TO_RIGHT); + byte[] scannedFingerprints = nfcGetFingerprints(); + + try { + long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(scannedFingerprints); + CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId); + ring.getMasterKeyId(); + + String userId = nfcGetUserId(); + byte[] nfcAid = nfcGetAid(); + + Intent intent = new Intent(this, ViewKeyActivity.class); + intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId)); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, userId); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, scannedFingerprints); + startActivity(intent); + finish(); + + } catch (PgpKeyNotFoundException e) { + Fragment frag = CreateKeyYubiFragment.createInstance(scannedFingerprints); + loadFragment(frag, FragAction.TO_RIGHT); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java index 63549c3d6..a1668d22e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java @@ -17,48 +17,33 @@ package org.sufficientlysecure.keychain.ui; -import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Arrays; import android.app.Activity; import android.content.Intent; import android.database.Cursor; -import android.net.Uri; import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import android.widget.ViewAnimator; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; -import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; -import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.ui.util.Notify.Style; -import org.sufficientlysecure.keychain.ui.widget.NameEditText; import org.sufficientlysecure.keychain.util.Preferences; - -public class CreateKeyYubiFragment extends Fragment - implements LoaderManager.LoaderCallbacks { +public class CreateKeyYubiFragment extends Fragment { private static final String ARG_FINGERPRINT = "fingerprint"; @@ -67,12 +52,7 @@ public class CreateKeyYubiFragment extends Fragment private byte[] mScannedFingerprint; private long mScannedMasterKeyId; - private ViewAnimator mAnimator; private TextView mUnknownFingerprint; - private TextView mFingerprint; - private TextView mUserId; - - private YubiImportState mState; public static Fragment createInstance(byte[] scannedFingerprint) { Bundle args = new Bundle(); @@ -91,26 +71,14 @@ public class CreateKeyYubiFragment extends Fragment mScannedFingerprint = getArguments().getByteArray(ARG_FINGERPRINT); mScannedMasterKeyId = getKeyIdFromFingerprint(mScannedFingerprint); - getLoaderManager().initLoader(0, null, this); - } - - enum YubiImportState { - UNKNOWN, // scanned unknown key (ready to import) - BAD_FINGERPRINT, // scanned key, bad fingerprint - IMPORTED, // imported key (ready to promote) } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.create_yubikey_fragment, container, false); - mAnimator = (ViewAnimator) view.findViewById(R.id.create_yubikey_animator); - mUnknownFingerprint = (TextView) view.findViewById(R.id.create_yubikey_unknown_fp); - mFingerprint = (TextView) view.findViewById(R.id.create_yubikey_fingerprint); - mUserId = (TextView) view.findViewById(R.id.create_yubikey_user_id); - View mBackButton = view.findViewById(R.id.create_key_back_button); View mNextButton = view.findViewById(R.id.create_key_next_button); @@ -136,115 +104,8 @@ public class CreateKeyYubiFragment extends Fragment mCreateKeyActivity = (CreateKeyActivity) getActivity(); } - // These are the rows that we will retrieve. - static final String[] UNIFIED_PROJECTION = new String[]{ - KeychainContract.KeyRings._ID, - KeychainContract.KeyRings.MASTER_KEY_ID, - KeychainContract.KeyRings.USER_ID, - KeychainContract.KeyRings.IS_REVOKED, - KeychainContract.KeyRings.IS_EXPIRED, - KeychainContract.KeyRings.HAS_ANY_SECRET, - KeychainContract.KeyRings.FINGERPRINT, - }; - - static final int INDEX_MASTER_KEY_ID = 1; - static final int INDEX_USER_ID = 2; - static final int INDEX_IS_REVOKED = 3; - static final int INDEX_IS_EXPIRED = 4; - static final int INDEX_HAS_ANY_SECRET = 5; - static final int INDEX_FINGERPRINT = 6; - - @Override - public Loader onCreateLoader(int id, Bundle args) { - Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri( - KeyRings.buildUnifiedKeyRingUri(mScannedMasterKeyId) - ); - return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - if (data.moveToFirst()) { - - byte[] fingerprint = data.getBlob(INDEX_FINGERPRINT); - if (!Arrays.equals(fingerprint, mScannedFingerprint)) { - mState = YubiImportState.BAD_FINGERPRINT; - Notify.create(getActivity(), "Fingerprint mismatch!", Style.ERROR); - return; - } - - String userId = data.getString(INDEX_USER_ID); - boolean hasSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; - - String fp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); - mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fp)); - - mUserId.setText(userId); - - mAnimator.setDisplayedChild(2); - mState = YubiImportState.IMPORTED; - - } else { - String fp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); - mUnknownFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fp)); - - mAnimator.setDisplayedChild(1); - mState = YubiImportState.UNKNOWN; - } - } - private void nextClicked() { - - switch (mState) { - case UNKNOWN: - importKey(); - break; - case IMPORTED: - promoteKey(); - break; - } - - } - - public void promoteKey() { - - // Message is received after decrypting is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity()) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == MessageStatus.OKAY.ordinal()) { - // get returned data bundle - Bundle returnData = message.getData(); - - PromoteKeyResult result = - returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); - - result.createNotify(getActivity()).show(); - } - - } - }; - - // Send all information needed to service to decrypt in other thread - Intent intent = new Intent(getActivity(), KeychainIntentService.class); - - // fill values for this action - - intent.setAction(KeychainIntentService.ACTION_PROMOTE_KEYRING); - - Bundle data = new Bundle(); - data.putLong(KeychainIntentService.PROMOTE_MASTER_KEY_ID, mScannedMasterKeyId); - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // start service with intent - getActivity().startService(intent); - + importKey(); } public void importKey() { @@ -299,12 +160,6 @@ public class CreateKeyYubiFragment extends Fragment } - - @Override - public void onLoaderReset(Loader loader) { - - } - static long getKeyIdFromFingerprint(byte[] fingerprint) { ByteBuffer buf = ByteBuffer.wrap(fingerprint); // skip first 12 bytes of the fingerprint diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index fc30eafcc..159b98e0e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -35,6 +35,7 @@ import android.os.Message; import android.os.Messenger; import android.provider.ContactsContract; import android.support.v4.app.ActivityCompat; +import android.support.v4.app.FragmentManager; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; @@ -60,18 +61,22 @@ import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus; import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.ui.base.BaseActivity; +import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.util.ExportHelper; @@ -79,12 +84,17 @@ import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.NfcHelper; import org.sufficientlysecure.keychain.util.Preferences; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; -public class ViewKeyActivity extends BaseActivity implements +public class ViewKeyActivity extends BaseNfcActivity implements LoaderManager.LoaderCallbacks { + public static final String EXTRA_NFC_USER_ID = "nfc_user_id"; + public static final String EXTRA_NFC_AID = "nfc_aid"; + public static final String EXTRA_NFC_FINGERPRINTS = "nfc_fingerprints"; + static final int REQUEST_QR_FINGERPRINT = 1; static final int REQUEST_DELETE = 2; static final int REQUEST_EXPORT = 3; @@ -107,6 +117,8 @@ public class ViewKeyActivity extends BaseActivity implements private ImageView mQrCode; private CardView mQrCodeLayout; + private String mQrCodeLoaded; + // NFC private NfcHelper mNfcHelper; @@ -257,6 +269,15 @@ public class ViewKeyActivity extends BaseActivity implements mNfcHelper.initNfc(mDataUri); startFragment(savedInstanceState, mDataUri); + + if (savedInstanceState == null && getIntent().hasExtra(EXTRA_NFC_AID)) { + Intent intent = getIntent(); + byte[] nfcFingerprints = intent.getByteArrayExtra(EXTRA_NFC_FINGERPRINTS); + String nfcUserId = intent.getStringExtra(EXTRA_NFC_USER_ID); + byte[] nfcAid = intent.getByteArrayExtra(EXTRA_NFC_AID); + showYubikeyFragment(nfcFingerprints, nfcUserId, nfcAid); + } + } @Override @@ -517,6 +538,60 @@ public class ViewKeyActivity extends BaseActivity implements } } + @Override + protected void onNfcPerform() throws IOException { + + final byte[] nfcFingerprints = nfcGetFingerprints(); + final String nfcUserId = nfcGetUserId(); + final byte[] nfcAid = nfcGetAid(); + + String fp = KeyFormattingUtils.convertFingerprintToHex(nfcFingerprints); + final long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(nfcFingerprints); + + if (!mFingerprint.equals(fp)) { + try { + CachedPublicKeyRing ring = mProviderHelper.getCachedPublicKeyRing(masterKeyId); + ring.getMasterKeyId(); + + Notify.create(this, "Different key stored on Yubikey!", Notify.LENGTH_LONG, + Style.WARN, new ActionListener() { + @Override + public void onAction() { + Intent intent = new Intent( + ViewKeyActivity.this, ViewKeyActivity.class); + intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId)); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints); + startActivity(intent); + finish(); + } + }, R.string.snack_yubikey_view).show(); + return; + + } catch (PgpKeyNotFoundException e) { + Notify.create(this, "Different key stored on Yubikey!", Style.ERROR).show(); + return; + } + } + + showYubikeyFragment(nfcFingerprints, nfcUserId, nfcAid); + + } + + public void showYubikeyFragment(byte[] nfcFingerprints, String nfcUserId, byte[] nfcAid) { + ViewKeyYubikeyFragment frag = ViewKeyYubikeyFragment.newInstance( + nfcFingerprints, nfcUserId, nfcAid); + + FragmentManager manager = getSupportFragmentManager(); + + manager.popBackStack("yubikey", FragmentManager.POP_BACK_STACK_INCLUSIVE); + manager.beginTransaction() + .addToBackStack("yubikey") + .replace(R.id.view_key_fragment, frag) + .commit(); + } + private void encrypt(Uri dataUri, boolean text) { // If there is no encryption key, don't bother. if (!mHasEncrypt) { @@ -648,6 +723,7 @@ public class ViewKeyActivity extends BaseActivity implements } protected void onPostExecute(Bitmap qrCode) { + mQrCodeLoaded = fingerprint; // scale the image up to our actual size. we do this in code rather // than let the ImageView do this because we don't require filtering. Bitmap scaled = Bitmap.createScaledBitmap(qrCode, @@ -725,7 +801,6 @@ public class ViewKeyActivity extends BaseActivity implements mName.setText(R.string.user_id_no_name); } - String oldFingerprint = mFingerprint; mMasterKeyId = data.getLong(INDEX_MASTER_KEY_ID); mFingerprint = KeyFormattingUtils.convertFingerprintToHex(data.getBlob(INDEX_FINGERPRINT)); @@ -789,7 +864,7 @@ public class ViewKeyActivity extends BaseActivity implements mStatusImage.setVisibility(View.GONE); color = getResources().getColor(R.color.primary); // reload qr code only if the fingerprint changed - if (!mFingerprint.equals(oldFingerprint)) { + if (!mFingerprint.equals(mQrCodeLoaded)) { loadQrCode(mFingerprint); } photoTask.execute(mMasterKeyId); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java new file mode 100644 index 000000000..7df791fbf --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java @@ -0,0 +1,129 @@ +package org.sufficientlysecure.keychain.ui; + + +import android.content.Intent; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.spongycastle.util.encoders.Hex; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; + + +public class ViewKeyYubikeyFragment extends Fragment { + + + public static final String ARG_FINGERPRINT = "fingerprint"; + public static final String ARG_USER_ID = "user_id"; + public static final String ARG_AID = "aid"; + private byte[] mFingerprints; + private String mUserId; + private byte[] mAid; + + public static ViewKeyYubikeyFragment newInstance(byte[] fingerprints, String userId, byte[] aid) { + + ViewKeyYubikeyFragment frag = new ViewKeyYubikeyFragment(); + + Bundle args = new Bundle(); + args.putByteArray(ARG_FINGERPRINT, fingerprints); + args.putString(ARG_USER_ID, userId); + args.putByteArray(ARG_AID, aid); + frag.setArguments(args); + + return frag; + + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle args = getArguments(); + mFingerprints = args.getByteArray(ARG_FINGERPRINT); + mUserId = args.getString(ARG_USER_ID); + mAid = args.getByteArray(ARG_AID); + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.view_key_yubikey, null); + + TextView vSerNo = (TextView) view.findViewById(R.id.yubikey_serno); + TextView vUserId = (TextView) view.findViewById(R.id.yubikey_userid); + + String serno = Hex.toHexString(mAid, 10, 4); + vSerNo.setText("Serial N° " + serno); + + if (!mUserId.isEmpty()) { + vUserId.setText("Key holder: " + mUserId); + } else { + vUserId.setText("Key holder: " + ""); + } + + view.findViewById(R.id.button_import).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + promoteToSecretKey(); + } + }); + + + return view; + } + + public void promoteToSecretKey() { + + // Message is received after decrypting is done in KeychainIntentService + KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity()) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == MessageStatus.OKAY.ordinal()) { + // get returned data bundle + Bundle returnData = message.getData(); + + PromoteKeyResult result = + returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); + + result.createNotify(getActivity()).show(); + } + + } + }; + + // Send all information needed to service to decrypt in other thread + Intent intent = new Intent(getActivity(), KeychainIntentService.class); + + // fill values for this action + + intent.setAction(KeychainIntentService.ACTION_PROMOTE_KEYRING); + + long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mFingerprints); + + Bundle data = new Bundle(); + data.putLong(KeychainIntentService.PROMOTE_MASTER_KEY_ID, masterKeyId); + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(saveHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // start service with intent + getActivity().startService(intent); + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index ca1d79155..2fd88fd66 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -248,12 +248,17 @@ public abstract class BaseNfcActivity extends BaseActivity { return fp; } + public byte[] nfcGetAid() throws IOException { + + String info = "00CA004F00"; + return mIsoDep.transceive(Hex.decode(info)); + + } public String nfcGetUserId() throws IOException { + String info = "00CA006500"; - String data = "00CA005E00"; - return nfcGetHolderName(nfcCommunicate(info)) + " <" + (new String(Hex.decode(nfcGetDataField( - nfcCommunicate(data))))) + ">"; + return nfcGetHolderName(nfcCommunicate(info)); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java index c5403e054..ae66b59d4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java @@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve; import org.sufficientlysecure.keychain.util.Log; +import java.nio.ByteBuffer; import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -215,7 +216,15 @@ public class KeyFormattingUtils { * @return */ public static String convertFingerprintToHex(byte[] fingerprint) { - return Hex.toHexString(fingerprint).toLowerCase(Locale.ENGLISH); + return Hex.toHexString(fingerprint, 0, 20).toLowerCase(Locale.ENGLISH); + } + + public static long getKeyIdFromFingerprint(byte[] fingerprint) { + ByteBuffer buf = ByteBuffer.wrap(fingerprint); + // skip first 12 bytes of the fingerprint + buf.position(12); + // the last eight bytes are the key id (big endian, which is default order in ByteBuffer) + return buf.getLong(); } /** -- cgit v1.2.3 From 22063cdd6eca32e83e7937a849e70185a1faee2a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 22 Mar 2015 03:34:34 +0100 Subject: improve status reporting in yubikey dialogue --- .../keychain/ui/ViewKeyYubikeyFragment.java | 113 +++++++++++++++++++-- 1 file changed, 102 insertions(+), 11 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java index 7df791fbf..f60b6f299 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java @@ -1,35 +1,48 @@ package org.sufficientlysecure.keychain.ui; +import java.nio.ByteBuffer; +import java.util.Arrays; + import android.content.Intent; +import android.database.Cursor; import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.widget.Button; import android.widget.TextView; import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; +import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -public class ViewKeyYubikeyFragment extends Fragment { - +public class ViewKeyYubikeyFragment extends Fragment + implements LoaderCallbacks { public static final String ARG_FINGERPRINT = "fingerprint"; public static final String ARG_USER_ID = "user_id"; public static final String ARG_AID = "aid"; - private byte[] mFingerprints; + private byte[][] mFingerprints; private String mUserId; private byte[] mAid; + private long mMasterKeyId; + private Button vButton; + private TextView vStatus; public static ViewKeyYubikeyFragment newInstance(byte[] fingerprints, String userId, byte[] aid) { @@ -50,10 +63,19 @@ public class ViewKeyYubikeyFragment extends Fragment { super.onCreate(savedInstanceState); Bundle args = getArguments(); - mFingerprints = args.getByteArray(ARG_FINGERPRINT); + ByteBuffer buf = ByteBuffer.wrap(args.getByteArray(ARG_FINGERPRINT)); + mFingerprints = new byte[buf.remaining()/40][]; + for (int i = 0; i < mFingerprints.length; i++) { + mFingerprints[i] = new byte[20]; + buf.get(mFingerprints[i]); + } mUserId = args.getString(ARG_USER_ID); mAid = args.getByteArray(ARG_AID); + mMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mFingerprints[0]); + + getLoaderManager().initLoader(0, null, this); + } @Override @@ -64,21 +86,23 @@ public class ViewKeyYubikeyFragment extends Fragment { TextView vUserId = (TextView) view.findViewById(R.id.yubikey_userid); String serno = Hex.toHexString(mAid, 10, 4); - vSerNo.setText("Serial N° " + serno); + vSerNo.setText(getString(R.string.yubikey_serno, serno)); if (!mUserId.isEmpty()) { - vUserId.setText("Key holder: " + mUserId); + vUserId.setText(getString(R.string.yubikey_key_holder, mUserId)); } else { - vUserId.setText("Key holder: " + ""); + vUserId.setText(getString(R.string.yubikey_key_holder_unset)); } - view.findViewById(R.id.button_import).setOnClickListener(new OnClickListener() { + vButton = (Button) view.findViewById(R.id.button_bind); + vButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { promoteToSecretKey(); } }); + vStatus = (TextView) view.findViewById(R.id.yubikey_status); return view; } @@ -111,10 +135,8 @@ public class ViewKeyYubikeyFragment extends Fragment { intent.setAction(KeychainIntentService.ACTION_PROMOTE_KEYRING); - long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mFingerprints); - Bundle data = new Bundle(); - data.putLong(KeychainIntentService.PROMOTE_MASTER_KEY_ID, masterKeyId); + data.putLong(KeychainIntentService.PROMOTE_MASTER_KEY_ID, mMasterKeyId); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Create a new Messenger for the communication back @@ -126,4 +148,73 @@ public class ViewKeyYubikeyFragment extends Fragment { } + public static final String[] PROJECTION = new String[]{ + Keys._ID, + Keys.KEY_ID, + Keys.RANK, + Keys.HAS_SECRET, + Keys.FINGERPRINT + }; + private static final int INDEX_KEY_ID = 1; + private static final int INDEX_RANK = 2; + private static final int INDEX_HAS_SECRET = 3; + private static final int INDEX_FINGERPRINT = 4; + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new CursorLoader(getActivity(), Keys.buildKeysUri(mMasterKeyId), + PROJECTION, null, null, null); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + if (!data.moveToFirst()) { + // wut? + return; + } + + boolean allBound = true; + boolean noneBound = true; + + do { + SecretKeyType keyType = SecretKeyType.fromNum(data.getInt(INDEX_HAS_SECRET)); + byte[] fingerprint = data.getBlob(INDEX_FINGERPRINT); + Integer index = naiveIndexOf(mFingerprints, fingerprint); + if (index == null) { + continue; + } + if (keyType == SecretKeyType.DIVERT_TO_CARD) { + noneBound = false; + } else { + allBound = false; + } + } while (data.moveToNext()); + + if (allBound) { + vButton.setVisibility(View.GONE); + vStatus.setText("Key matches, fully bound"); + } else { + vButton.setVisibility(View.VISIBLE); + if (noneBound) { + vStatus.setText("Key matches, can be bound"); + } else { + vStatus.setText("Key matches, partly bound"); + } + } + + } + + public Integer naiveIndexOf(byte[][] haystack, byte[] needle) { + for (int i = 0; i < haystack.length; i++) { + if (Arrays.equals(needle, haystack[i])) { + return i; + } + } + return null; + } + + @Override + public void onLoaderReset(Loader loader) { + + } } -- cgit v1.2.3 From 2151411219b4e5d609d25fcbb574ccf399f54d6f Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 22 Mar 2015 03:56:58 +0100 Subject: actually promote to divert, pass yubikey's AID --- .../keychain/ui/ViewKeyYubikeyFragment.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java index f60b6f299..192d85d58 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java @@ -36,10 +36,10 @@ public class ViewKeyYubikeyFragment extends Fragment public static final String ARG_FINGERPRINT = "fingerprint"; public static final String ARG_USER_ID = "user_id"; - public static final String ARG_AID = "aid"; + public static final String ARG_CARD_AID = "aid"; private byte[][] mFingerprints; private String mUserId; - private byte[] mAid; + private byte[] mCardAid; private long mMasterKeyId; private Button vButton; private TextView vStatus; @@ -51,7 +51,7 @@ public class ViewKeyYubikeyFragment extends Fragment Bundle args = new Bundle(); args.putByteArray(ARG_FINGERPRINT, fingerprints); args.putString(ARG_USER_ID, userId); - args.putByteArray(ARG_AID, aid); + args.putByteArray(ARG_CARD_AID, aid); frag.setArguments(args); return frag; @@ -70,7 +70,7 @@ public class ViewKeyYubikeyFragment extends Fragment buf.get(mFingerprints[i]); } mUserId = args.getString(ARG_USER_ID); - mAid = args.getByteArray(ARG_AID); + mCardAid = args.getByteArray(ARG_CARD_AID); mMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mFingerprints[0]); @@ -85,7 +85,7 @@ public class ViewKeyYubikeyFragment extends Fragment TextView vSerNo = (TextView) view.findViewById(R.id.yubikey_serno); TextView vUserId = (TextView) view.findViewById(R.id.yubikey_userid); - String serno = Hex.toHexString(mAid, 10, 4); + String serno = Hex.toHexString(mCardAid, 10, 4); vSerNo.setText(getString(R.string.yubikey_serno, serno)); if (!mUserId.isEmpty()) { @@ -137,6 +137,7 @@ public class ViewKeyYubikeyFragment extends Fragment Bundle data = new Bundle(); data.putLong(KeychainIntentService.PROMOTE_MASTER_KEY_ID, mMasterKeyId); + data.putByteArray(KeychainIntentService.PROMOTE_CARD_AID, mCardAid); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Create a new Messenger for the communication back @@ -192,13 +193,13 @@ public class ViewKeyYubikeyFragment extends Fragment if (allBound) { vButton.setVisibility(View.GONE); - vStatus.setText("Key matches, fully bound"); + vStatus.setText(R.string.yubikey_status_bound); } else { vButton.setVisibility(View.VISIBLE); if (noneBound) { - vStatus.setText("Key matches, can be bound"); + vStatus.setText(R.string.yubikey_status_unbound); } else { - vStatus.setText("Key matches, partly bound"); + vStatus.setText(R.string.yubikey_status_partly); } } -- cgit v1.2.3 From 212bba18693ebfce2dfa62afde8b11e8f0c2da0d Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 22 Mar 2015 06:36:27 +0100 Subject: finish ui flow for yubikey import --- .../keychain/ui/CreateKeyActivity.java | 45 ++-- .../keychain/ui/CreateKeyYubiFragment.java | 171 -------------- .../keychain/ui/CreateKeyYubiImportFragment.java | 256 +++++++++++++++++++++ .../keychain/ui/ImportKeysListFragment.java | 26 ++- .../keychain/ui/ViewKeyActivity.java | 20 +- .../keychain/ui/ViewKeyYubikeyFragment.java | 8 +- 6 files changed, 329 insertions(+), 197 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index b73d6f545..0b203614b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import org.sufficientlysecure.keychain.R; @@ -29,9 +30,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; -import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.Passphrase; import java.io.IOException; @@ -45,6 +43,10 @@ public class CreateKeyActivity extends BaseNfcActivity { public static final String EXTRA_ADDITIONAL_EMAILS = "additional_emails"; public static final String EXTRA_PASSPHRASE = "passphrase"; + public static final String EXTRA_NFC_USER_ID = "nfc_user_id"; + public static final String EXTRA_NFC_AID = "nfc_aid"; + public static final String EXTRA_NFC_FINGERPRINTS = "nfc_fingerprints"; + public static final String FRAGMENT_TAG = "currentFragment"; String mName; @@ -70,14 +72,29 @@ public class CreateKeyActivity extends BaseNfcActivity { mCurrentFragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG); } else { + + Intent intent = getIntent(); // Initialize members with default values for a new instance - mName = getIntent().getStringExtra(EXTRA_NAME); - mEmail = getIntent().getStringExtra(EXTRA_EMAIL); - mFirstTime = getIntent().getBooleanExtra(EXTRA_FIRST_TIME, false); + mName = intent.getStringExtra(EXTRA_NAME); + mEmail = intent.getStringExtra(EXTRA_EMAIL); + mFirstTime = intent.getBooleanExtra(EXTRA_FIRST_TIME, false); + + if (intent.hasExtra(EXTRA_NFC_FINGERPRINTS)) { + byte[] nfcFingerprints = intent.getByteArrayExtra(EXTRA_NFC_FINGERPRINTS); + String nfcUserId = intent.getStringExtra(EXTRA_NFC_USER_ID); + byte[] nfcAid = intent.getByteArrayExtra(EXTRA_NFC_AID); + + Fragment frag2 = CreateKeyYubiImportFragment.createInstance( + nfcFingerprints, nfcAid, nfcUserId); + loadFragment(frag2, FragAction.START); + + setTitle(R.string.title_import_keys); + return; + } else { + CreateKeyStartFragment frag = CreateKeyStartFragment.newInstance(); + loadFragment(frag, FragAction.START); + } - // Start with first fragment of wizard - CreateKeyStartFragment frag = CreateKeyStartFragment.newInstance(); - loadFragment(frag, FragAction.START); } if (mFirstTime) { @@ -97,15 +114,14 @@ public class CreateKeyActivity extends BaseNfcActivity { } byte[] scannedFingerprints = nfcGetFingerprints(); + byte[] nfcAid = nfcGetAid(); + String userId = nfcGetUserId(); try { long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(scannedFingerprints); CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId); ring.getMasterKeyId(); - String userId = nfcGetUserId(); - byte[] nfcAid = nfcGetAid(); - Intent intent = new Intent(this, ViewKeyActivity.class); intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId)); intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid); @@ -115,7 +131,8 @@ public class CreateKeyActivity extends BaseNfcActivity { finish(); } catch (PgpKeyNotFoundException e) { - Fragment frag = CreateKeyYubiFragment.createInstance(scannedFingerprints); + Fragment frag = CreateKeyYubiImportFragment.createInstance( + scannedFingerprints, nfcAid, userId); loadFragment(frag, FragAction.TO_RIGHT); } @@ -167,8 +184,10 @@ public class CreateKeyActivity extends BaseNfcActivity { break; } + // do it immediately! getSupportFragmentManager().executePendingTransactions(); + } interface NfcListenerFragment { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java deleted file mode 100644 index a1668d22e..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiFragment.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * 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 java.nio.ByteBuffer; -import java.util.ArrayList; - -import android.app.Activity; -import android.content.Intent; -import android.database.Cursor; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.support.v4.app.Fragment; -import android.support.v4.app.LoaderManager; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; -import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; -import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.Preferences; - -public class CreateKeyYubiFragment extends Fragment { - - private static final String ARG_FINGERPRINT = "fingerprint"; - - CreateKeyActivity mCreateKeyActivity; - - private byte[] mScannedFingerprint; - private long mScannedMasterKeyId; - - private TextView mUnknownFingerprint; - - public static Fragment createInstance(byte[] scannedFingerprint) { - Bundle args = new Bundle(); - args.putByteArray(ARG_FINGERPRINT, scannedFingerprint); - - CreateKeyYubiFragment frag = new CreateKeyYubiFragment(); - frag.setArguments(args); - - return frag; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mScannedFingerprint = getArguments().getByteArray(ARG_FINGERPRINT); - mScannedMasterKeyId = getKeyIdFromFingerprint(mScannedFingerprint); - - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.create_yubikey_fragment, container, false); - - mUnknownFingerprint = (TextView) view.findViewById(R.id.create_yubikey_unknown_fp); - - View mBackButton = view.findViewById(R.id.create_key_back_button); - View mNextButton = view.findViewById(R.id.create_key_next_button); - - mBackButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT); - } - }); - mNextButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - nextClicked(); - } - }); - - return view; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - mCreateKeyActivity = (CreateKeyActivity) getActivity(); - } - - private void nextClicked() { - importKey(); - } - - public void importKey() { - - // Message is received after decrypting is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity()) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == MessageStatus.OKAY.ordinal()) { - // get returned data bundle - Bundle returnData = message.getData(); - - ImportKeyResult result = - returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); - - result.createNotify(getActivity()).show(); - } - - } - }; - - // Send all information needed to service to decrypt in other thread - Intent intent = new Intent(getActivity(), KeychainIntentService.class); - - // fill values for this action - Bundle data = new Bundle(); - - intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING); - - String hexFp = KeyFormattingUtils.convertFingerprintToHex(mScannedFingerprint); - ArrayList keyList = new ArrayList<>(); - keyList.add(new ParcelableKeyRing(hexFp, null, null)); - data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, keyList); - - { - Preferences prefs = Preferences.getPreferences(getActivity()); - Preferences.CloudSearchPrefs cloudPrefs = - new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver()); - data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver); - } - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // start service with intent - getActivity().startService(intent); - - } - - static long getKeyIdFromFingerprint(byte[] fingerprint) { - ByteBuffer buf = ByteBuffer.wrap(fingerprint); - // skip first 12 bytes of the fingerprint - buf.position(12); - // the last eight bytes are the key id (big endian, which is default order in ByteBuffer) - return buf.getLong(); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java new file mode 100644 index 000000000..bb26a4ede --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyYubiImportFragment.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * 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 java.io.IOException; +import java.util.ArrayList; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Intent; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.spongycastle.util.encoders.Hex; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; +import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Preferences; + + +public class CreateKeyYubiImportFragment extends Fragment implements NfcListenerFragment { + + private static final String ARG_FINGERPRINT = "fingerprint"; + public static final String ARG_AID = "aid"; + public static final String ARG_USER_ID = "user_ids"; + + CreateKeyActivity mCreateKeyActivity; + + private byte[] mNfcFingerprints; + private long mNfcMasterKeyId; + private byte[] mNfcAid; + private String mNfcUserId; + private String mNfcFingerprint; + private ImportKeysListFragment mListFragment; + private TextView vSerNo; + private TextView vUserId; + + public static Fragment createInstance(byte[] scannedFingerprints, byte[] nfcAid, String userId) { + + CreateKeyYubiImportFragment frag = new CreateKeyYubiImportFragment(); + + Bundle args = new Bundle(); + args.putByteArray(ARG_FINGERPRINT, scannedFingerprints); + args.putByteArray(ARG_AID, nfcAid); + args.putString(ARG_USER_ID, userId); + frag.setArguments(args); + + return frag; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle args = savedInstanceState != null ? savedInstanceState : getArguments(); + + mNfcFingerprints = args.getByteArray(ARG_FINGERPRINT); + mNfcAid = args.getByteArray(ARG_AID); + mNfcUserId = args.getString(ARG_USER_ID); + + mNfcMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints); + mNfcFingerprint = KeyFormattingUtils.convertFingerprintToHex(mNfcFingerprints); + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.create_yubikey_import_fragment, container, false); + + vSerNo = (TextView) view.findViewById(R.id.yubikey_serno); + vUserId = (TextView) view.findViewById(R.id.yubikey_userid); + + { + View mBackButton = view.findViewById(R.id.create_key_back_button); + mBackButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (getFragmentManager().getBackStackEntryCount() == 0) { + getActivity().setResult(Activity.RESULT_CANCELED); + getActivity().finish(); + } else { + mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT); + } + } + }); + + View mNextButton = view.findViewById(R.id.create_key_next_button); + mNextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + importKey(); + } + }); + } + + mListFragment = ImportKeysListFragment.newInstance(null, null, "0x" + mNfcFingerprint, true); + + view.findViewById(R.id.button_search).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + refreshSearch(); + } + }); + + setData(); + + getFragmentManager().beginTransaction() + .replace(R.id.yubikey_import_fragment, mListFragment, "yubikey_import") + .commit(); + + return view; + } + + @Override + public void onSaveInstanceState(Bundle args) { + super.onSaveInstanceState(args); + + args.putByteArray(ARG_FINGERPRINT, mNfcFingerprints); + args.putByteArray(ARG_AID, mNfcAid); + args.putString(ARG_USER_ID, mNfcUserId); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mCreateKeyActivity = (CreateKeyActivity) getActivity(); + } + + public void setData() { + String serno = Hex.toHexString(mNfcAid, 10, 4); + vSerNo.setText(getString(R.string.yubikey_serno, serno)); + + if (!mNfcUserId.isEmpty()) { + vUserId.setText(getString(R.string.yubikey_key_holder, mNfcUserId)); + } else { + vUserId.setText(getString(R.string.yubikey_key_holder_unset)); + } + } + + public void refreshSearch() { + mListFragment.loadNew(new ImportKeysListFragment.CloudLoaderState("0x" + mNfcFingerprint, + Preferences.getPreferences(getActivity()).getCloudSearchPrefs())); + } + + public void importKey() { + + // Message is received after decrypting is done in KeychainIntentService + KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), + getString(R.string.progress_importing), ProgressDialog.STYLE_HORIZONTAL) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == MessageStatus.OKAY.ordinal()) { + // get returned data bundle + Bundle returnData = message.getData(); + + ImportKeyResult result = + returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); + + if (!result.success()) { + result.createNotify(getActivity()).show(); + return; + } + + Intent intent = new Intent(getActivity(), ViewKeyActivity.class); + intent.setData(KeyRings.buildGenericKeyRingUri(mNfcMasterKeyId)); + intent.putExtra(ViewKeyActivity.EXTRA_DISPLAY_RESULT, result); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, mNfcAid); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, mNfcUserId); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, mNfcFingerprints); + startActivity(intent); + getActivity().finish(); + + } + + } + }; + + // Send all information needed to service to decrypt in other thread + Intent intent = new Intent(getActivity(), KeychainIntentService.class); + + // fill values for this action + Bundle data = new Bundle(); + + intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING); + + String hexFp = KeyFormattingUtils.convertFingerprintToHex(mNfcFingerprints); + ArrayList keyList = new ArrayList<>(); + keyList.add(new ParcelableKeyRing(hexFp, null, null)); + data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, keyList); + + { + Preferences prefs = Preferences.getPreferences(getActivity()); + Preferences.CloudSearchPrefs cloudPrefs = + new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver()); + data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver); + } + + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(saveHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + saveHandler.showProgressDialog(getActivity()); + + // start service with intent + getActivity().startService(intent); + + } + + @Override + public void onNfcPerform() throws IOException { + + mNfcFingerprints = mCreateKeyActivity.nfcGetFingerprints(); + mNfcAid = mCreateKeyActivity.nfcGetAid(); + mNfcUserId = mCreateKeyActivity.nfcGetUserId(); + + mNfcMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints); + mNfcFingerprint = KeyFormattingUtils.convertFingerprintToHex(mNfcFingerprints); + + setData(); + refreshSearch(); + + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java index 6a6140892..b9fdbea5c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -53,9 +53,11 @@ import java.util.List; public class ImportKeysListFragment extends ListFragment implements LoaderManager.LoaderCallbacks>> { + private static final String ARG_DATA_URI = "uri"; private static final String ARG_BYTES = "bytes"; - private static final String ARG_SERVER_QUERY = "query"; + public static final String ARG_SERVER_QUERY = "query"; + public static final String ARG_NON_INTERACTIVE = "non_interactive"; private Activity mActivity; private ImportKeysAdapter mAdapter; @@ -66,6 +68,7 @@ public class ImportKeysListFragment extends ListFragment implements private static final int LOADER_ID_CLOUD = 1; private LongSparseArray mCachedKeyData; + private boolean mNonInteractive; public LoaderState getLoaderState() { return mLoaderState; @@ -118,16 +121,19 @@ public class ImportKeysListFragment extends ListFragment implements } - /** - * Creates new instance of this fragment - */ public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, String serverQuery) { + return newInstance(bytes, dataUri, serverQuery, false); + } + + public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, + String serverQuery, boolean nonInteractive) { ImportKeysListFragment frag = new ImportKeysListFragment(); Bundle args = new Bundle(); args.putByteArray(ARG_BYTES, bytes); args.putParcelable(ARG_DATA_URI, dataUri); args.putString(ARG_SERVER_QUERY, serverQuery); + args.putBoolean(ARG_NON_INTERACTIVE, nonInteractive); frag.setArguments(args); @@ -173,9 +179,11 @@ public class ImportKeysListFragment extends ListFragment implements mAdapter = new ImportKeysAdapter(mActivity); setListAdapter(mAdapter); - Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); - byte[] bytes = getArguments().getByteArray(ARG_BYTES); - String query = getArguments().getString(ARG_SERVER_QUERY); + Bundle args = getArguments(); + Uri dataUri = args.containsKey(ARG_DATA_URI) ? args.getParcelable(ARG_DATA_URI) : null; + byte[] bytes = args.containsKey(ARG_BYTES) ? args.getByteArray(ARG_BYTES) : null; + String query = args.containsKey(ARG_SERVER_QUERY) ? args.getString(ARG_SERVER_QUERY) : null; + mNonInteractive = args.containsKey(ARG_NON_INTERACTIVE) ? args.getBoolean(ARG_NON_INTERACTIVE) : false; if (dataUri != null || bytes != null) { mLoaderState = new BytesLoaderState(bytes, dataUri); @@ -203,6 +211,10 @@ public class ImportKeysListFragment extends ListFragment implements public void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); + if (mNonInteractive) { + return; + } + // Select checkbox! // Update underlying data and notify adapter of change. The adapter will // update the view automatically. diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 159b98e0e..3d298ea6c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -98,6 +98,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements static final int REQUEST_QR_FINGERPRINT = 1; static final int REQUEST_DELETE = 2; static final int REQUEST_EXPORT = 3; + public static final String EXTRA_DISPLAY_RESULT = "display_result"; ExportHelper mExportHelper; ProviderHelper mProviderHelper; @@ -268,6 +269,11 @@ public class ViewKeyActivity extends BaseNfcActivity implements mNfcHelper = new NfcHelper(this, mProviderHelper); mNfcHelper.initNfc(mDataUri); + if (savedInstanceState == null && getIntent().hasExtra(EXTRA_DISPLAY_RESULT)) { + OperationResult result = getIntent().getParcelableExtra(EXTRA_DISPLAY_RESULT); + result.createNotify(this).show(); + } + startFragment(savedInstanceState, mDataUri); if (savedInstanceState == null && getIntent().hasExtra(EXTRA_NFC_AID)) { @@ -570,7 +576,19 @@ public class ViewKeyActivity extends BaseNfcActivity implements return; } catch (PgpKeyNotFoundException e) { - Notify.create(this, "Different key stored on Yubikey!", Style.ERROR).show(); + Notify.create(this, "Different key stored on Yubikey!", Notify.LENGTH_LONG, + Style.WARN, new ActionListener() { + @Override + public void onAction() { + Intent intent = new Intent( + ViewKeyActivity.this, CreateKeyActivity.class); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints); + startActivity(intent); + finish(); + } + }, R.string.snack_yubikey_import).show(); return; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java index 192d85d58..1d87bef3e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java @@ -196,11 +196,9 @@ public class ViewKeyYubikeyFragment extends Fragment vStatus.setText(R.string.yubikey_status_bound); } else { vButton.setVisibility(View.VISIBLE); - if (noneBound) { - vStatus.setText(R.string.yubikey_status_unbound); - } else { - vStatus.setText(R.string.yubikey_status_partly); - } + vStatus.setText(noneBound + ? R.string.yubikey_status_unbound + : R.string.yubikey_status_partly); } } -- cgit v1.2.3 From 2e838e4cce32a5926466b6069a58c6a3579c12bf Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 22 Mar 2015 06:48:33 +0100 Subject: enable nfc in import dialog as well --- .../keychain/ui/ImportKeysActivity.java | 4 +- .../keychain/ui/ViewKeyActivity.java | 4 +- .../keychain/ui/base/BaseNfcActivity.java | 46 +++++++++++++++++++++- 3 files changed, 49 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') 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 9a7c405d0..72ae1c73a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.base.BaseActivity; +import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; @@ -47,7 +48,8 @@ import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize import java.io.IOException; import java.util.ArrayList; -public class ImportKeysActivity extends BaseActivity { +public class ImportKeysActivity extends BaseNfcActivity { + public static final String ACTION_IMPORT_KEY = OpenKeychainIntents.IMPORT_KEY; public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = OpenKeychainIntents.IMPORT_KEY_FROM_KEYSERVER; public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT = diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 3d298ea6c..fad477de3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -559,7 +559,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements CachedPublicKeyRing ring = mProviderHelper.getCachedPublicKeyRing(masterKeyId); ring.getMasterKeyId(); - Notify.create(this, "Different key stored on Yubikey!", Notify.LENGTH_LONG, + Notify.create(this, R.string.snack_yubi_other, Notify.LENGTH_LONG, Style.WARN, new ActionListener() { @Override public void onAction() { @@ -576,7 +576,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements return; } catch (PgpKeyNotFoundException e) { - Notify.create(this, "Different key stored on Yubikey!", Notify.LENGTH_LONG, + Notify.create(this, R.string.snack_yubi_other, Notify.LENGTH_LONG, Style.WARN, new ActionListener() { @Override public void onAction() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index 2fd88fd66..2c2cb6067 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -16,9 +16,20 @@ import android.widget.Toast; import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; +import org.sufficientlysecure.keychain.ui.CreateKeyActivity; import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; +import org.sufficientlysecure.keychain.ui.ViewKeyActivity; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; @@ -190,7 +201,38 @@ public abstract class BaseNfcActivity extends BaseActivity { } - protected abstract void onNfcPerform() throws IOException; + protected void onNfcPerform() throws IOException { + + final byte[] nfcFingerprints = nfcGetFingerprints(); + final String nfcUserId = nfcGetUserId(); + final byte[] nfcAid = nfcGetAid(); + + String fp = KeyFormattingUtils.convertFingerprintToHex(nfcFingerprints); + final long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(nfcFingerprints); + + try { + CachedPublicKeyRing ring = new ProviderHelper(this).getCachedPublicKeyRing(masterKeyId); + ring.getMasterKeyId(); + + Intent intent = new Intent( + BaseNfcActivity.this, ViewKeyActivity.class); + intent.setData(KeyRings.buildGenericKeyRingUri(masterKeyId)); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_AID, nfcAid); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_USER_ID, nfcUserId); + intent.putExtra(ViewKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints); + startActivity(intent); + finish(); + } catch (PgpKeyNotFoundException e) { + Intent intent = new Intent( + BaseNfcActivity.this, CreateKeyActivity.class); + intent.putExtra(CreateKeyActivity.EXTRA_NFC_AID, nfcAid); + intent.putExtra(CreateKeyActivity.EXTRA_NFC_USER_ID, nfcUserId); + intent.putExtra(CreateKeyActivity.EXTRA_NFC_FINGERPRINTS, nfcFingerprints); + startActivity(intent); + finish(); + } + + } /** Return the key id from application specific data stored on tag, or null * if it doesn't exist. @@ -242,7 +284,7 @@ public abstract class BaseNfcActivity extends BaseActivity { // return the master key fingerprint ByteBuffer fpbuf = ByteBuffer.wrap(data); byte[] fp = new byte[20]; - fpbuf.position(idx*20); + fpbuf.position(idx * 20); fpbuf.get(fp, 0, 20); return fp; -- cgit v1.2.3 From 3bb194fc080e5945dc8bdbeea9b91cf801406c32 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 23 Mar 2015 01:09:39 +0100 Subject: nicer handling of nfc errors --- .../keychain/ui/base/BaseNfcActivity.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index 2c2cb6067..365d32918 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -28,7 +28,6 @@ import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; import org.sufficientlysecure.keychain.ui.ViewKeyActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; @@ -68,14 +67,18 @@ public abstract class BaseNfcActivity extends BaseActivity { try { handleNdefDiscoveredIntent(intent); } catch (IOException e) { - Log.e(Constants.TAG, "Connection error!", e); - toast("Connection Error: " + e.getMessage()); - setResult(RESULT_CANCELED); - finish(); + handleNfcError(e); } } } + public void handleNfcError(IOException e) { + + Log.e(Constants.TAG, "nfc error", e); + Notify.create(this, getString(R.string.error_nfc, e.getMessage()), Style.WARN).show(); + + } + /** * Called when the system is about to start resuming a previous activity, * disables NFC Foreground Dispatch -- cgit v1.2.3 From c694d73cab1edf91cb94d53cc8352ca93f0eb6ce Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 23 Mar 2015 01:44:14 +0100 Subject: further improve yubikey error handling --- .../keychain/ui/NfcOperationActivity.java | 22 ++++++++++++++ .../keychain/ui/base/BaseNfcActivity.java | 35 +++++++++++----------- 2 files changed, 39 insertions(+), 18 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index 549d9ece7..511183b04 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -14,10 +14,12 @@ import android.view.WindowManager; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; import java.io.IOException; @@ -89,4 +91,24 @@ public class NfcOperationActivity extends BaseNfcActivity { finish(); } + + @Override + public void handlePinError() { + + // avoid a loop + Preferences prefs = Preferences.getPreferences(this); + if (prefs.useDefaultYubikeyPin()) { + toast(getString(R.string.error_pin_nodefault)); + setResult(RESULT_CANCELED); + finish(); + return; + } + + // clear (invalid) passphrase + PassphraseCacheService.clearCachedPassphrase( + this, mRequiredInput.getMasterKeyId(), mRequiredInput.getSubKeyId()); + + obtainYubikeyPin(RequiredInputParcel.createRequiredPassphrase(mRequiredInput)); + + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index 365d32918..a8a5a1f28 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -79,6 +79,12 @@ public abstract class BaseNfcActivity extends BaseActivity { } + public void handlePinError() { + toast("Wrong PIN!"); + setResult(RESULT_CANCELED); + finish(); + } + /** * Called when the system is about to start resuming a previous activity, * disables NFC Foreground Dispatch @@ -170,10 +176,7 @@ public abstract class BaseNfcActivity extends BaseActivity { + "D27600012401" // Data (6 bytes) + "00"; // Le if ( ! nfcCommunicate(opening).equals(accepted)) { // activate connection - toast("Opening Error!"); - setResult(RESULT_CANCELED); - finish(); - return; + throw new IOException("Initialization failed!"); } if (mPin != null) { @@ -189,9 +192,7 @@ public abstract class BaseNfcActivity extends BaseActivity { + String.format("%02x", pin.length) // Lc + Hex.toHexString(pin); if (!nfcCommunicate(login).equals(accepted)) { // login - toast("Wrong PIN!"); - setResult(RESULT_CANCELED); - finish(); + handlePinError(); return; } @@ -321,7 +322,7 @@ public abstract class BaseNfcActivity extends BaseActivity { switch (hashAlgo) { case HashAlgorithmTags.SHA1: if (hash.length != 20) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 10!"); + throw new IOException("Bad hash length (" + hash.length + ", expected 10!"); } dsi = "23" // Lc + "3021" // Tag/Length of Sequence, the 0x21 includes all following 33 bytes @@ -332,36 +333,36 @@ public abstract class BaseNfcActivity extends BaseActivity { break; case HashAlgorithmTags.RIPEMD160: if (hash.length != 20) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 20!"); + throw new IOException("Bad hash length (" + hash.length + ", expected 20!"); } dsi = "233021300906052B2403020105000414" + getHex(hash); break; case HashAlgorithmTags.SHA224: if (hash.length != 28) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 28!"); + throw new IOException("Bad hash length (" + hash.length + ", expected 28!"); } dsi = "2F302D300D06096086480165030402040500041C" + getHex(hash); break; case HashAlgorithmTags.SHA256: if (hash.length != 32) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 32!"); + throw new IOException("Bad hash length (" + hash.length + ", expected 32!"); } dsi = "333031300D060960864801650304020105000420" + getHex(hash); break; case HashAlgorithmTags.SHA384: if (hash.length != 48) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 48!"); + throw new IOException("Bad hash length (" + hash.length + ", expected 48!"); } dsi = "433041300D060960864801650304020205000430" + getHex(hash); break; case HashAlgorithmTags.SHA512: if (hash.length != 64) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 64!"); + throw new IOException("Bad hash length (" + hash.length + ", expected 64!"); } dsi = "533051300D060960864801650304020305000440" + getHex(hash); break; default: - throw new RuntimeException("Not supported hash algo!"); + throw new IOException("Not supported hash algo!"); } // Command APDU for PERFORM SECURITY OPERATION: COMPUTE DIGITAL SIGNATURE (page 37) @@ -388,14 +389,12 @@ public abstract class BaseNfcActivity extends BaseActivity { Log.d(Constants.TAG, "final response:" + status); if ( ! "9000".equals(status)) { - toast("Bad NFC response code: " + status); - return null; + throw new IOException("Bad NFC response code: " + status); } // Make sure the signature we received is actually the expected number of bytes long! if (signature.length() != 256 && signature.length() != 512) { - toast("Bad signature length! Expected 128 or 256 bytes, got " + signature.length() / 2); - return null; + throw new IOException("Bad signature length! Expected 128 or 256 bytes, got " + signature.length() / 2); } return Hex.decode(signature); -- cgit v1.2.3 From 5e024bba2e7b5a0d91735488f9d31850cbf81d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 25 Mar 2015 10:50:55 +0100 Subject: Remove backward compat in CertifyKeyFragment --- .../keychain/ui/CertifyKeyFragment.java | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index a669fcc8c..44773e501 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -25,8 +25,6 @@ import android.database.Cursor; import android.database.MatrixCursor; import android.graphics.PorterDuff; import android.net.Uri; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Message; import android.os.Messenger; @@ -55,19 +53,16 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.ServiceProgressHandler; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner; import org.sufficientlysecure.keychain.ui.widget.KeySpinner; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Preferences; -import java.lang.reflect.Method; import java.util.ArrayList; @@ -218,17 +213,6 @@ public class CertifyKeyFragment extends CryptoOperationFragment }) { @Override public byte[] getBlob(int column) { - // For some reason, getBlob was not implemented before ICS - if (VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) { - try { - // haha, yes there is int.class - Method m = MatrixCursor.class.getDeclaredMethod("get", new Class[]{int.class}); - m.setAccessible(true); - return (byte[]) m.invoke(this, 1); - } catch (Exception e) { - throw new UnsupportedOperationException(e); - } - } return super.getBlob(column); } }; -- cgit v1.2.3 From 1ef63f31879f599851058c0d36918df4fb671fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 25 Mar 2015 11:12:52 +0100 Subject: Fix certify with CryptoInputParcel --- .../sufficientlysecure/keychain/ui/CertifyKeyFragment.java | 2 +- .../org/sufficientlysecure/keychain/ui/EditKeyFragment.java | 2 +- .../keychain/ui/EncryptDecryptOverviewFragment.java | 12 ++++-------- 3 files changed, 6 insertions(+), 10 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index 44773e501..20a280a54 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -164,7 +164,7 @@ public class CertifyKeyFragment extends CryptoOperationFragment Notify.create(getActivity(), getString(R.string.select_key_to_certify), Notify.Style.ERROR).show(); } else { - cryptoOperation(null); + cryptoOperation(new CryptoInputParcel()); } } }); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index 2375c1d30..bf17c2991 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -151,7 +151,7 @@ public class EditKeyFragment extends CryptoOperationFragment implements if (mDataUri == null) { returnKeyringParcel(); } else { - cryptoOperation(new CryptoInputParcel(new Date())); + cryptoOperation(new CryptoInputParcel()); } } }, new OnClickListener() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java index a498d0763..a6fad8881 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java @@ -37,10 +37,6 @@ import java.util.regex.Matcher; public class EncryptDecryptOverviewFragment extends Fragment { - View mEncryptFile; - View mEncryptText; - View mDecryptFile; - View mDecryptFromClipboard; View mClipboardIcon; @Override @@ -53,10 +49,10 @@ public class EncryptDecryptOverviewFragment extends Fragment { public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.encrypt_decrypt_overview_fragment, container, false); - mEncryptFile = view.findViewById(R.id.encrypt_files); - mEncryptText = view.findViewById(R.id.encrypt_text); - mDecryptFile = view.findViewById(R.id.decrypt_files); - mDecryptFromClipboard = view.findViewById(R.id.decrypt_from_clipboard); + View mEncryptFile = view.findViewById(R.id.encrypt_files); + View mEncryptText = view.findViewById(R.id.encrypt_text); + View mDecryptFile = view.findViewById(R.id.decrypt_files); + View mDecryptFromClipboard = view.findViewById(R.id.decrypt_from_clipboard); mClipboardIcon = view.findViewById(R.id.clipboard_icon); mEncryptFile.setOnClickListener(new View.OnClickListener() { -- cgit v1.2.3 From 76db0b3b8e8c474a50e17b165657c1a24f8e6be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 26 Mar 2015 11:04:20 +0100 Subject: Start refactoring encrypt ui, EncryptFileActivity no longer crashing --- .../keychain/ui/CryptoOperationFragment.java | 3 +- .../keychain/ui/EncryptAsymmetricFragment.java | 84 ++-- .../keychain/ui/EncryptFilesActivity.java | 432 +++----------------- .../keychain/ui/EncryptFilesFragment.java | 436 +++++++++++++++++++-- .../keychain/ui/EncryptSymmetricFragment.java | 35 +- .../keychain/ui/EncryptTextActivity.java | 47 +-- 6 files changed, 531 insertions(+), 506 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java index 592c7db22..076c628b4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java @@ -51,8 +51,9 @@ public abstract class CryptoOperationFragment extends Fragment { CryptoInputParcel cryptoInput = data.getParcelableExtra(PassphraseDialogActivity.RESULT_DATA); cryptoOperation(cryptoInput); + return; } - return; + break; } case REQUEST_CODE_NFC: { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index c5404094a..06c711b92 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Dominik Schürmann + * Copyright (C) 2014-2015 Dominik Schürmann * * 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 @@ -40,7 +40,17 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -public class EncryptAsymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener { +public class EncryptAsymmetricFragment extends Fragment { + + public interface IAsymmetric { + + public void onSignatureKeyIdChanged(long signatureKeyId); + + public void onEncryptionKeyIdsChanged(long[] encryptionKeyIds); + + public void onEncryptionUserIdsChanged(String[] encryptionUserIds); + } + ProviderHelper mProviderHelper; // view @@ -48,37 +58,43 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi private EncryptKeyCompletionView mEncryptKeyView; // model - private EncryptActivityInterface mEncryptInterface; + private IAsymmetric mEncryptInterface; - @Override - public void onNotifyUpdate() { - if (mSign != null) { - mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey()); - } +// @Override +// public void onNotifyUpdate() { +// if (mSign != null) { +// mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey()); +// } +// } + + public static final String ARG_SINGATURE_KEY_ID = "signature_key_id"; + public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids"; + + + /** + * Creates new instance of this fragment + */ + public static EncryptAsymmetricFragment newInstance(long signatureKey, long[] encryptionKeyIds) { + EncryptAsymmetricFragment frag = new EncryptAsymmetricFragment(); + + Bundle args = new Bundle(); + args.putLong(ARG_SINGATURE_KEY_ID, signatureKey); + args.putLongArray(ARG_ENCRYPTION_KEY_IDS, encryptionKeyIds); + frag.setArguments(args); + + return frag; } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { - mEncryptInterface = (EncryptActivityInterface) activity; + mEncryptInterface = (IAsymmetric) activity; } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface"); + throw new ClassCastException(activity.toString() + " must implement IAsymmetric"); } } - private void setSignatureKeyId(long signatureKeyId) { - mEncryptInterface.setSignatureKey(signatureKeyId); - } - - private void setEncryptionKeyIds(long[] encryptionKeyIds) { - mEncryptInterface.setEncryptionKeys(encryptionKeyIds); - } - - private void setEncryptionUserIds(String[] encryptionUserIds) { - mEncryptInterface.setEncryptionUsers(encryptionUserIds); - } - /** * Inflate the layout for this fragment */ @@ -90,7 +106,7 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi mSign.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() { @Override public void onKeyChanged(long masterKeyId) { - setSignatureKeyId(masterKeyId); + mEncryptInterface.onSignatureKeyIdChanged(masterKeyId); } }); mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list); @@ -105,7 +121,9 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi mProviderHelper = new ProviderHelper(getActivity()); // preselect keys given - preselectKeys(); + long signatureKeyId = getArguments().getLong(ARG_SINGATURE_KEY_ID); + long[] encryptionKeyIds = getArguments().getLongArray(ARG_ENCRYPTION_KEY_IDS); + preselectKeys(signatureKeyId, encryptionKeyIds); mEncryptKeyView.setTokenListener(new TokenCompleteTextView.TokenListener() { @Override @@ -127,24 +145,20 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi /** * If an Intent gives a signatureMasterKeyId and/or encryptionMasterKeyIds, preselect those! */ - private void preselectKeys() { - // TODO all of this works under the assumption that the first suitable subkey is always used! - // not sure if we need to distinguish between different subkeys here? - long signatureKey = mEncryptInterface.getSignatureKey(); - if (signatureKey != Constants.key.none) { + private void preselectKeys(long signatureKeyId, long[] encryptionKeyIds) { + if (signatureKeyId != Constants.key.none) { try { CachedPublicKeyRing keyring = mProviderHelper.getCachedPublicKeyRing( - KeyRings.buildUnifiedKeyRingUri(signatureKey)); + KeyRings.buildUnifiedKeyRingUri(signatureKeyId)); if (keyring.hasAnySecret()) { - setSignatureKeyId(keyring.getMasterKeyId()); - mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey()); + mEncryptInterface.onSignatureKeyIdChanged(keyring.getMasterKeyId()); + mSign.setSelectedKeyId(signatureKeyId); } } catch (PgpKeyNotFoundException e) { Log.e(Constants.TAG, "key not found!", e); } } - long[] encryptionKeyIds = mEncryptInterface.getEncryptionKeys(); if (encryptionKeyIds != null) { for (long preselectedId : encryptionKeyIds) { try { @@ -176,7 +190,7 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi for (int i = 0; i < keyIds.size(); i++) { keyIdsArr[i] = iterator.next(); } - setEncryptionKeyIds(keyIdsArr); - setEncryptionUserIds(userIds.toArray(new String[userIds.size()])); + mEncryptInterface.onEncryptionKeyIdsChanged(keyIdsArr); + mEncryptInterface.onEncryptionUserIdsChanged(userIds.toArray(new String[userIds.size()])); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java index ac54ebff6..269fdde8e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2012-2015 Dominik Schürmann * Copyright (C) 2010-2014 Thialfihar * * This program is free software: you can redistribute it and/or modify @@ -22,28 +22,19 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; -import android.view.Menu; -import android.view.MenuItem; +import android.support.v4.app.FragmentTransaction; -import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.api.OpenKeychainIntents; -import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; -import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConstants; -import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; -import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; -import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.util.Passphrase; -import org.sufficientlysecure.keychain.util.ShareHelper; import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; -public class EncryptFilesActivity extends EncryptActivity implements EncryptActivityInterface { +public class EncryptFilesActivity extends BaseActivity implements + EncryptAsymmetricFragment.IAsymmetric, EncryptSymmetricFragment.ISymmetric, + EncryptFilesFragment.IMode { /* Intents */ public static final String ACTION_ENCRYPT_DATA = OpenKeychainIntents.ENCRYPT_DATA; @@ -55,301 +46,15 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi public static final String EXTRA_SIGNATURE_KEY_ID = Constants.EXTRA_PREFIX + "EXTRA_SIGNATURE_KEY_ID"; public static final String EXTRA_ENCRYPTION_KEY_IDS = Constants.EXTRA_PREFIX + "EXTRA_ENCRYPTION_IDS"; - // view - private int mCurrentMode = MODE_ASYMMETRIC; - - // tabs - private static final int MODE_ASYMMETRIC = 0; - private static final int MODE_SYMMETRIC = 1; - - // model used by fragments - private boolean mUseArmor = false; - private boolean mUseCompression = true; - private boolean mDeleteAfterEncrypt = false; - private boolean mShareAfterEncrypt = false; - private boolean mEncryptFilenames = true; - private boolean mHiddenRecipients = false; - - private long mEncryptionKeyIds[] = null; - private String mEncryptionUserIds[] = null; - private long mSigningKeyId = Constants.key.none; - private Passphrase mPassphrase = new Passphrase(); - - private ArrayList mInputUris; - private ArrayList mOutputUris; - private String mMessage = ""; - - public boolean isModeSymmetric() { - return MODE_SYMMETRIC == mCurrentMode; - } - - @Override - public boolean isUseArmor() { - return mUseArmor; - } - - @Override - public boolean isUseCompression() { - return mUseCompression; - } - - @Override - public boolean isEncryptFilenames() { - return mEncryptFilenames; - } - - @Override - public boolean isHiddenRecipients() { - return mHiddenRecipients; - } - - @Override - public long getSignatureKey() { - return mSigningKeyId; - } - - @Override - public long[] getEncryptionKeys() { - return mEncryptionKeyIds; - } - - @Override - public String[] getEncryptionUsers() { - return mEncryptionUserIds; - } - - @Override - public void setSignatureKey(long signatureKey) { - mSigningKeyId = signatureKey; - notifyUpdate(); - } - - @Override - public void setEncryptionKeys(long[] encryptionKeys) { - mEncryptionKeyIds = encryptionKeys; - notifyUpdate(); - } - - @Override - public void setEncryptionUsers(String[] encryptionUsers) { - mEncryptionUserIds = encryptionUsers; - notifyUpdate(); - } - - @Override - public void setPassphrase(Passphrase passphrase) { - mPassphrase = passphrase; - } - - @Override - public ArrayList getInputUris() { - if (mInputUris == null) mInputUris = new ArrayList<>(); - return mInputUris; - } - - @Override - public ArrayList getOutputUris() { - if (mOutputUris == null) mOutputUris = new ArrayList<>(); - return mOutputUris; - } - - @Override - public void setInputUris(ArrayList uris) { - mInputUris = uris; - notifyUpdate(); - } - - @Override - public void setOutputUris(ArrayList uris) { - mOutputUris = uris; - notifyUpdate(); - } - - @Override - public String getMessage() { - return mMessage; - } - - @Override - public void setMessage(String message) { - mMessage = message; - } - - @Override - public void notifyUpdate() { - for (Fragment fragment : getSupportFragmentManager().getFragments()) { - if (fragment instanceof EncryptActivityInterface.UpdateListener) { - ((UpdateListener) fragment).onNotifyUpdate(); - } - } - } - - @Override - public void startEncrypt(boolean share) { - mShareAfterEncrypt = share; - startEncrypt(); - } - - @Override - public void onEncryptSuccess(final SignEncryptResult result) { - if (mDeleteAfterEncrypt) { - final Uri[] inputUris = mInputUris.toArray(new Uri[mInputUris.size()]); - DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(inputUris); - deleteFileDialog.setOnDeletedListener(new DeleteFileDialogFragment.OnDeletedListener() { - - @Override - public void onDeleted() { - if (mShareAfterEncrypt) { - // Share encrypted message/file - startActivity(sendWithChooserExcludingEncrypt()); - } else { - // Save encrypted file - result.createNotify(EncryptFilesActivity.this).show(); - } - } - - }); - deleteFileDialog.show(getSupportFragmentManager(), "deleteDialog"); - - mInputUris.clear(); - notifyUpdate(); - } else { - if (mShareAfterEncrypt) { - // Share encrypted message/file - startActivity(sendWithChooserExcludingEncrypt()); - } else { - // Save encrypted file - result.createNotify(EncryptFilesActivity.this).show(); - } - } - } - - @Override - protected SignEncryptParcel createEncryptBundle() { - // fill values for this action - SignEncryptParcel data = new SignEncryptParcel(); - - data.addInputUris(mInputUris); - data.addOutputUris(mOutputUris); - - if (mUseCompression) { - data.setCompressionId(PgpConstants.sPreferredCompressionAlgorithms.get(0)); - } else { - data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED); - } - data.setHiddenRecipients(mHiddenRecipients); - data.setEnableAsciiArmorOutput(mUseArmor); - data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); - data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); - - if (isModeSymmetric()) { - Log.d(Constants.TAG, "Symmetric encryption enabled!"); - Passphrase passphrase = mPassphrase; - if (passphrase.isEmpty()) { - passphrase = null; - } - data.setSymmetricPassphrase(passphrase); - } else { - data.setEncryptionMasterKeyIds(mEncryptionKeyIds); - data.setSignatureMasterKeyId(mSigningKeyId); - data.setSignaturePassphrase(mSigningKeyPassphrase); - } - return data; - } - - /** - * Create Intent Chooser but exclude OK's EncryptActivity. - */ - private Intent sendWithChooserExcludingEncrypt() { - Intent prototype = createSendIntent(); - String title = getString(R.string.title_share_file); - - // we don't want to encrypt the encrypted, no inception ;) - String[] blacklist = new String[]{ - Constants.PACKAGE_NAME + ".ui.EncryptFileActivity", - "org.thialfihar.android.apg.ui.EncryptActivity" - }; - - return new ShareHelper(this).createChooserExcluding(prototype, title, blacklist); - } - - private Intent createSendIntent() { - Intent sendIntent; - // file - if (mOutputUris.size() == 1) { - sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_STREAM, mOutputUris.get(0)); - } else { - sendIntent = new Intent(Intent.ACTION_SEND_MULTIPLE); - sendIntent.putExtra(Intent.EXTRA_STREAM, mOutputUris); - } - sendIntent.setType(Constants.ENCRYPTED_FILES_MIME); - - if (!isModeSymmetric() && mEncryptionUserIds != null) { - Set users = new HashSet<>(); - for (String user : mEncryptionUserIds) { - KeyRing.UserId userId = KeyRing.splitUserId(user); - if (userId.email != null) { - users.add(userId.email); - } - } - sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()])); - } - return sendIntent; - } - - protected boolean inputIsValid() { - // file checks - - if (mInputUris.isEmpty()) { - Notify.create(this, R.string.no_file_selected, Notify.Style.ERROR) - .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_file_fragment)); - return false; - } else if (mInputUris.size() > 1 && !mShareAfterEncrypt) { - // This should be impossible... - return false; - } else if (mInputUris.size() != mOutputUris.size()) { - // This as well - return false; - } - - if (isModeSymmetric()) { - // symmetric encryption checks - - if (mPassphrase == null) { - Notify.create(this, R.string.passphrases_do_not_match, Notify.Style.ERROR) - .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_file_fragment)); - return false; - } - if (mPassphrase.isEmpty()) { - Notify.create(this, R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) - .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_file_fragment)); - return false; - } - - } else { - // asymmetric encryption checks - - boolean gotEncryptionKeys = (mEncryptionKeyIds != null - && mEncryptionKeyIds.length > 0); - - // Files must be encrypted, only text can be signed-only right now - if (!gotEncryptionKeys) { - Notify.create(this, R.string.select_encryption_key, Notify.Style.ERROR) - .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_file_fragment)); - return false; - } - } - return true; - } + Fragment mModeFragment; + EncryptFilesFragment mEncryptFragment; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Handle intent actions - handleActions(getIntent()); - updateModeFragment(); + handleActions(getIntent(), savedInstanceState); } @Override @@ -357,73 +62,10 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi setContentView(R.layout.encrypt_files_activity); } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.encrypt_file_activity, menu); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.isCheckable()) { - item.setChecked(!item.isChecked()); - } - switch (item.getItemId()) { - case R.id.check_use_symmetric: { - mCurrentMode = item.isChecked() ? MODE_SYMMETRIC : MODE_ASYMMETRIC; - updateModeFragment(); - notifyUpdate(); - break; - } - case R.id.check_use_armor: { - mUseArmor = item.isChecked(); - notifyUpdate(); - break; - } - case R.id.check_delete_after_encrypt: { - mDeleteAfterEncrypt = item.isChecked(); - notifyUpdate(); - break; - } - case R.id.check_enable_compression: { - mUseCompression = item.isChecked(); - notifyUpdate(); - break; - } - case R.id.check_encrypt_filenames: { - mEncryptFilenames = item.isChecked(); - notifyUpdate(); - break; - } -// case R.id.check_hidden_recipients: { -// mHiddenRecipients = item.isChecked(); -// notifyUpdate(); -// break; -// } - default: { - return super.onOptionsItemSelected(item); - } - } - return true; - } - - private void updateModeFragment() { - getSupportFragmentManager().beginTransaction() - .replace(R.id.encrypt_pager_mode, - mCurrentMode == MODE_SYMMETRIC - ? new EncryptSymmetricFragment() - : new EncryptAsymmetricFragment() - ) - .commitAllowingStateLoss(); - getSupportFragmentManager().executePendingTransactions(); - } - /** * Handles all actions with this intent - * - * @param intent */ - private void handleActions(Intent intent) { + private void handleActions(Intent intent, Bundle savedInstanceState) { String action = intent.getAction(); Bundle extras = intent.getExtras(); String type = intent.getType(); @@ -452,14 +94,56 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); } - mUseArmor = extras.getBoolean(EXTRA_ASCII_ARMOR, false); + long mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID); + long[] mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS); + boolean useArmor = extras.getBoolean(EXTRA_ASCII_ARMOR, false); + + if (savedInstanceState == null) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + + mModeFragment = EncryptAsymmetricFragment.newInstance(mSigningKeyId, mEncryptionKeyIds); + transaction.replace(R.id.encrypt_mode_container, mModeFragment, "mode"); + + mEncryptFragment = EncryptFilesFragment.newInstance(uris, useArmor); + transaction.replace(R.id.encrypt_file_container, mEncryptFragment, "files"); + + transaction.commit(); + + getSupportFragmentManager().executePendingTransactions(); + } + } + + @Override + public void onModeChanged(boolean symmetric) { + // switch fragments + getSupportFragmentManager().beginTransaction() + .replace(R.id.encrypt_mode_container, + symmetric + ? EncryptSymmetricFragment.newInstance() + : EncryptAsymmetricFragment.newInstance(0, null) + ) + .commitAllowingStateLoss(); + getSupportFragmentManager().executePendingTransactions(); + } - // preselect keys given by intent - mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID); - mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS); + @Override + public void onSignatureKeyIdChanged(long signatureKeyId) { + mEncryptFragment.setSigningKeyId(signatureKeyId); + } + + @Override + public void onEncryptionKeyIdsChanged(long[] encryptionKeyIds) { + mEncryptFragment.setEncryptionKeyIds(encryptionKeyIds); + } - // Save uris - mInputUris = uris; + @Override + public void onEncryptionUserIdsChanged(String[] encryptionUserIds) { + mEncryptFragment.setEncryptionUserIds(encryptionUserIds); + } + + @Override + public void onPassphraseChanged(Passphrase passphrase) { + mEncryptFragment.setPassphrase(passphrase); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 4ba76d8ea..771800245 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -19,14 +19,18 @@ package org.sufficientlysecure.keychain.ui; import android.annotation.TargetApi; import android.app.Activity; +import android.app.ProgressDialog; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Point; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.v4.app.Fragment; +import android.os.Message; +import android.os.Messenger; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; @@ -35,39 +39,108 @@ import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; +import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.PgpConstants; +import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.FileHelper; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; +import org.sufficientlysecure.keychain.util.ShareHelper; import java.io.File; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Set; -public class EncryptFilesFragment extends Fragment implements EncryptActivityInterface.UpdateListener { - public static final String ARG_URIS = "uris"; +public class EncryptFilesFragment extends CryptoOperationFragment { private static final int REQUEST_CODE_INPUT = 0x00007003; private static final int REQUEST_CODE_OUTPUT = 0x00007007; - private EncryptActivityInterface mEncryptInterface; + public interface IMode { + + public void onModeChanged(boolean symmetric); + } + + private IMode mModeInterface; + + // model used by fragments + private boolean mSymmetricMode = true; + private boolean mUseArmor = false; + private boolean mUseCompression = true; + private boolean mDeleteAfterEncrypt = false; + private boolean mShareAfterEncrypt = false; + private boolean mEncryptFilenames = true; + private boolean mHiddenRecipients = false; + + private long mEncryptionKeyIds[] = null; + private String mEncryptionUserIds[] = null; + private long mSigningKeyId = Constants.key.none; + private Passphrase mPassphrase = new Passphrase(); + + private ArrayList mInputUris = new ArrayList(); + private ArrayList mOutputUris = new ArrayList(); - // view - private View mAddView; private ListView mSelectedFiles; private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter(); private final Map thumbnailCache = new HashMap<>(); + + public static final String ARG_USE_ASCII_ARMOR = "use_ascii_armor"; + public static final String ARG_URIS = "uris"; + + + /** + * Creates new instance of this fragment + */ + public static EncryptFilesFragment newInstance(ArrayList uris, boolean useArmor) { + EncryptFilesFragment frag = new EncryptFilesFragment(); + + Bundle args = new Bundle(); + args.putBoolean(ARG_USE_ASCII_ARMOR, useArmor); + args.putParcelableArrayList(ARG_URIS, uris); + frag.setArguments(args); + + return frag; + } + + public void setEncryptionKeyIds(long[] encryptionKeyIds) { + mEncryptionKeyIds = encryptionKeyIds; + } + + public void setEncryptionUserIds(String[] encryptionUserIds) { + mEncryptionUserIds = encryptionUserIds; + } + + public void setSigningKeyId(long signingKeyId) { + mSigningKeyId = signingKeyId; + } + + public void setPassphrase(Passphrase passphrase) { + mPassphrase = passphrase; + } + @Override public void onAttach(Activity activity) { super.onAttach(activity); try { - mEncryptInterface = (EncryptActivityInterface) activity; + mModeInterface = (IMode) activity; } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface"); + throw new ClassCastException(activity.toString() + " must be IMode"); } } @@ -78,15 +151,15 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.encrypt_files_fragment, container, false); - mAddView = inflater.inflate(R.layout.file_list_entry_add, null); - mAddView.setOnClickListener(new View.OnClickListener() { + View addView = inflater.inflate(R.layout.file_list_entry_add, null); + addView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { addInputUri(); } }); mSelectedFiles = (ListView) view.findViewById(R.id.selected_files_list); - mSelectedFiles.addFooterView(mAddView); + mSelectedFiles.addFooterView(addView); mSelectedFiles.setAdapter(mAdapter); return view; @@ -95,16 +168,18 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setHasOptionsMenu(true); + + mInputUris = getArguments().getParcelableArrayList(ARG_URIS); + mUseArmor = getArguments().getBoolean(ARG_USE_ASCII_ARMOR); } private void addInputUri() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { FileHelper.openDocument(EncryptFilesFragment.this, "*/*", true, REQUEST_CODE_INPUT); } else { - FileHelper.openFile(EncryptFilesFragment.this, mEncryptInterface.getInputUris().isEmpty() ? - null : mEncryptInterface.getInputUris().get(mEncryptInterface.getInputUris().size() - 1), + FileHelper.openFile(EncryptFilesFragment.this, mInputUris.isEmpty() ? + null : mInputUris.get(mInputUris.size() - 1), "*/*", REQUEST_CODE_INPUT); } } @@ -114,32 +189,30 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt return; } - if (mEncryptInterface.getInputUris().contains(inputUri)) { + if (mInputUris.contains(inputUri)) { Notify.create(getActivity(), getActivity().getString(R.string.error_file_added_already, FileHelper.getFilename(getActivity(), inputUri)), Notify.Style.ERROR).show(this); return; } - mEncryptInterface.getInputUris().add(inputUri); - mEncryptInterface.notifyUpdate(); + mInputUris.add(inputUri); mSelectedFiles.requestFocus(); } private void delInputUri(int position) { - mEncryptInterface.getInputUris().remove(position); - mEncryptInterface.notifyUpdate(); + mInputUris.remove(position); mSelectedFiles.requestFocus(); } private void showOutputFileDialog() { - if (mEncryptInterface.getInputUris().size() > 1 || mEncryptInterface.getInputUris().isEmpty()) { + if (mInputUris.size() > 1 || mInputUris.isEmpty()) { throw new IllegalStateException(); } - Uri inputUri = mEncryptInterface.getInputUris().get(0); + Uri inputUri = mInputUris.get(0); String targetName = - (mEncryptInterface.isEncryptFilenames() ? "1" : FileHelper.getFilename(getActivity(), inputUri)) - + (mEncryptInterface.isUseArmor() ? Constants.FILE_EXTENSION_ASC : Constants.FILE_EXTENSION_PGP_MAIN); + (mEncryptFilenames ? "1" : FileHelper.getFilename(getActivity(), inputUri)) + + (mUseArmor ? Constants.FILE_EXTENSION_ASC : Constants.FILE_EXTENSION_PGP_MAIN); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { File file = new File(inputUri.getPath()); File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR; @@ -152,23 +225,23 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt } private void encryptClicked(boolean share) { - if (mEncryptInterface.getInputUris().isEmpty()) { + if (mInputUris.isEmpty()) { Notify.create(getActivity(), R.string.error_no_file_selected, Notify.Style.ERROR).show(this); return; } if (share) { - mEncryptInterface.getOutputUris().clear(); + mOutputUris.clear(); int filenameCounter = 1; - for (Uri uri : mEncryptInterface.getInputUris()) { + for (Uri uri : mInputUris) { String targetName = - (mEncryptInterface.isEncryptFilenames() ? String.valueOf(filenameCounter) : FileHelper.getFilename(getActivity(), uri)) - + (mEncryptInterface.isUseArmor() ? Constants.FILE_EXTENSION_ASC : Constants.FILE_EXTENSION_PGP_MAIN); - mEncryptInterface.getOutputUris().add(TemporaryStorageProvider.createFile(getActivity(), targetName)); + (mEncryptFilenames ? String.valueOf(filenameCounter) : FileHelper.getFilename(getActivity(), uri)) + + (mUseArmor ? Constants.FILE_EXTENSION_ASC : Constants.FILE_EXTENSION_PGP_MAIN); + mOutputUris.add(TemporaryStorageProvider.createFile(getActivity(), targetName)); filenameCounter++; } - mEncryptInterface.startEncrypt(true); + startEncrypt(true); } else { - if (mEncryptInterface.getInputUris().size() > 1) { + if (mInputUris.size() > 1) { Notify.create(getActivity(), R.string.error_multi_not_supported, Notify.Style.ERROR).show(this); return; } @@ -188,8 +261,17 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt return false; } + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.encrypt_file_activity, menu); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { + if (item.isCheckable()) { + item.setChecked(!item.isChecked()); + } switch (item.getItemId()) { case R.id.encrypt_save: { encryptClicked(false); @@ -199,6 +281,36 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt encryptClicked(true); break; } + case R.id.check_use_symmetric: { + mSymmetricMode = item.isChecked(); + mModeInterface.onModeChanged(mSymmetricMode); + break; + } + case R.id.check_use_armor: { + mUseArmor = item.isChecked(); +// notifyUpdate(); + break; + } + case R.id.check_delete_after_encrypt: { + mDeleteAfterEncrypt = item.isChecked(); +// notifyUpdate(); + break; + } + case R.id.check_enable_compression: { + mUseCompression = item.isChecked(); +// onNotifyUpdate(); + break; + } + case R.id.check_encrypt_filenames: { + mEncryptFilenames = item.isChecked(); +// onNotifyUpdate(); + break; + } +// case R.id.check_hidden_recipients: { +// mHiddenRecipients = item.isChecked(); +// notifyUpdate(); +// break; +// } default: { return super.onOptionsItemSelected(item); } @@ -206,6 +318,251 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt return true; } + protected boolean inputIsValid() { + // file checks + + if (mInputUris.isEmpty()) { + Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR) + .show(this); + return false; + } else if (mInputUris.size() > 1 && !mShareAfterEncrypt) { + // This should be impossible... + return false; + } else if (mInputUris.size() != mOutputUris.size()) { + // This as well + return false; + } + + if (mSymmetricMode) { + // symmetric encryption checks + + if (mPassphrase == null) { + Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR) + .show(this); + return false; + } + if (mPassphrase.isEmpty()) { + Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) + .show(this); + return false; + } + + } else { + // asymmetric encryption checks + + boolean gotEncryptionKeys = (mEncryptionKeyIds != null + && mEncryptionKeyIds.length > 0); + + // Files must be encrypted, only text can be signed-only right now + if (!gotEncryptionKeys) { + Notify.create(getActivity(), R.string.select_encryption_key, Notify.Style.ERROR) + .show(this); + return false; + } + } + return true; + } + + public void startEncrypt(boolean share) { + mShareAfterEncrypt = share; + startEncrypt(); + } + + public void onEncryptSuccess(final SignEncryptResult result) { + if (mDeleteAfterEncrypt) { + final Uri[] inputUris = mInputUris.toArray(new Uri[mInputUris.size()]); + DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(inputUris); + deleteFileDialog.setOnDeletedListener(new DeleteFileDialogFragment.OnDeletedListener() { + + @Override + public void onDeleted() { + if (mShareAfterEncrypt) { + // Share encrypted message/file + startActivity(sendWithChooserExcludingEncrypt()); + } else { + // Save encrypted file + result.createNotify(getActivity()).show(); + } + } + + }); + deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog"); + + mInputUris.clear(); + onNotifyUpdate(); + } else { + if (mShareAfterEncrypt) { + // Share encrypted message/file + startActivity(sendWithChooserExcludingEncrypt()); + } else { + // Save encrypted file + result.createNotify(getActivity()).show(); + } + } + } + + protected SignEncryptParcel createEncryptBundle() { + // fill values for this action + SignEncryptParcel data = new SignEncryptParcel(); + + data.addInputUris(mInputUris); + data.addOutputUris(mOutputUris); + + if (mUseCompression) { + data.setCompressionId(PgpConstants.sPreferredCompressionAlgorithms.get(0)); + } else { + data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED); + } + data.setHiddenRecipients(mHiddenRecipients); + data.setEnableAsciiArmorOutput(mUseArmor); + data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); + data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); + + if (mSymmetricMode) { + Log.d(Constants.TAG, "Symmetric encryption enabled!"); + Passphrase passphrase = mPassphrase; + if (passphrase.isEmpty()) { + passphrase = null; + } + data.setSymmetricPassphrase(passphrase); + } else { + data.setEncryptionMasterKeyIds(mEncryptionKeyIds); + data.setSignatureMasterKeyId(mSigningKeyId); +// data.setSignaturePassphrase(mSigningKeyPassphrase); + } + return data; + } + + /** + * Create Intent Chooser but exclude OK's EncryptActivity. + */ + private Intent sendWithChooserExcludingEncrypt() { + Intent prototype = createSendIntent(); + String title = getString(R.string.title_share_file); + + // we don't want to encrypt the encrypted, no inception ;) + String[] blacklist = new String[]{ + Constants.PACKAGE_NAME + ".ui.EncryptFileActivity", + "org.thialfihar.android.apg.ui.EncryptActivity" + }; + + return new ShareHelper(getActivity()).createChooserExcluding(prototype, title, blacklist); + } + + private Intent createSendIntent() { + Intent sendIntent; + // file + if (mOutputUris.size() == 1) { + sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_STREAM, mOutputUris.get(0)); + } else { + sendIntent = new Intent(Intent.ACTION_SEND_MULTIPLE); + sendIntent.putExtra(Intent.EXTRA_STREAM, mOutputUris); + } + sendIntent.setType(Constants.ENCRYPTED_FILES_MIME); + + if (!mSymmetricMode && mEncryptionUserIds != null) { + Set users = new HashSet<>(); + for (String user : mEncryptionUserIds) { + KeyRing.UserId userId = KeyRing.splitUserId(user); + if (userId.email != null) { + users.add(userId.email); + } + } + sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()])); + } + return sendIntent; + } + + public void startEncrypt() { + cryptoOperation(new CryptoInputParcel()); + } + + // public void startEncrypt(CryptoInputParcel cryptoInput) { + @Override + protected void cryptoOperation(CryptoInputParcel cryptoInput) { + + if (!inputIsValid()) { + // Notify was created by inputIsValid. + return; + } + + // Send all information needed to service to edit key in other thread + Intent intent = new Intent(getActivity(), KeychainIntentService.class); + intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); + + final SignEncryptParcel input = createEncryptBundle(); + if (cryptoInput != null) { + input.setCryptoInput(cryptoInput); + } + + Bundle data = new Bundle(); + data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Message is received after encrypting is done in KeychainIntentService + ServiceProgressHandler serviceHandler = new ServiceProgressHandler( + getActivity(), + getString(R.string.progress_encrypting), + ProgressDialog.STYLE_HORIZONTAL, + true, + ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + // handle pending messages + if (handlePendingMessage(message)) { + return; + } + + if (message.arg1 == MessageStatus.OKAY.ordinal()) { + SignEncryptResult result = + message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); + +// PgpSignEncryptResult pgpResult = result.getPending(); +// +// if (pgpResult != null && pgpResult.isPending()) { +// if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == +// PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { +// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); +// } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == +// PgpSignEncryptResult.RESULT_PENDING_NFC) { +// +// RequiredInputParcel parcel = RequiredInputParcel.createNfcSignOperation( +// pgpResult.getNfcHash(), +// pgpResult.getNfcAlgo(), +// input.getSignatureTime()); +// startNfcSign(pgpResult.getNfcKeyId(), parcel); +// +// } else { +// throw new RuntimeException("Unhandled pending result!"); +// } +// return; +// } + + if (result.success()) { + onEncryptSuccess(result); + } else { + result.createNotify(getActivity()).show(); + } + + // no matter the result, reset parameters +// mSigningKeyPassphrase = null; + } + } + }; + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(serviceHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // show progress dialog + serviceHandler.showProgressDialog(getActivity()); + + // start service with intent + getActivity().startService(intent); + } + @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { @@ -220,10 +577,10 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt case REQUEST_CODE_OUTPUT: { // This happens after output file was selected, so start our operation if (resultCode == Activity.RESULT_OK && data != null) { - mEncryptInterface.getOutputUris().clear(); - mEncryptInterface.getOutputUris().add(data.getData()); - mEncryptInterface.notifyUpdate(); - mEncryptInterface.startEncrypt(false); + mOutputUris.clear(); + mOutputUris.add(data.getData()); + onNotifyUpdate(); + startEncrypt(false); } return; } @@ -236,11 +593,10 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt } } - @Override public void onNotifyUpdate() { // Clear cache if needed for (Uri uri : new HashSet<>(thumbnailCache.keySet())) { - if (!mEncryptInterface.getInputUris().contains(uri)) { + if (!mInputUris.contains(uri)) { thumbnailCache.remove(uri); } } @@ -251,12 +607,12 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt private class SelectedFilesAdapter extends BaseAdapter { @Override public int getCount() { - return mEncryptInterface.getInputUris().size(); + return mInputUris.size(); } @Override public Object getItem(int position) { - return mEncryptInterface.getInputUris().get(position); + return mInputUris.get(position); } @Override @@ -266,7 +622,7 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt @Override public View getView(final int position, View convertView, ViewGroup parent) { - Uri inputUri = mEncryptInterface.getInputUris().get(position); + Uri inputUri = mInputUris.get(position); View view; if (convertView == null) { view = getActivity().getLayoutInflater().inflate(R.layout.file_list_entry, null); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java index 36b3c08f9..22e116a42 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Dominik Schürmann + * Copyright (C) 2014-2015 Dominik Schürmann * * 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 @@ -30,20 +30,37 @@ import android.widget.EditText; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.Passphrase; -public class EncryptSymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener { +public class EncryptSymmetricFragment extends Fragment { - EncryptActivityInterface mEncryptInterface; + public interface ISymmetric { + + public void onPassphraseChanged(Passphrase passphrase); + } + + private ISymmetric mEncryptInterface; private EditText mPassphrase; private EditText mPassphraseAgain; + /** + * Creates new instance of this fragment + */ + public static EncryptSymmetricFragment newInstance() { + EncryptSymmetricFragment frag = new EncryptSymmetricFragment(); + + Bundle args = new Bundle(); + frag.setArguments(args); + + return frag; + } + @Override public void onAttach(Activity activity) { super.onAttach(activity); try { - mEncryptInterface = (EncryptActivityInterface) activity; + mEncryptInterface = (ISymmetric) activity; } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface"); + throw new ClassCastException(activity.toString() + " must implement ISymmetric"); } } @@ -74,9 +91,9 @@ public class EncryptSymmetricFragment extends Fragment implements EncryptActivit p1.removeFromMemory(); p2.removeFromMemory(); if (passesEquals) { - mEncryptInterface.setPassphrase(new Passphrase(mPassphrase.getText())); + mEncryptInterface.onPassphraseChanged(new Passphrase(mPassphrase.getText())); } else { - mEncryptInterface.setPassphrase(null); + mEncryptInterface.onPassphraseChanged(null); } } }; @@ -86,8 +103,4 @@ public class EncryptSymmetricFragment extends Fragment implements EncryptActivit return view; } - @Override - public void onNotifyUpdate() { - - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 6d472abb4..56f0b198e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -21,7 +21,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.v4.app.Fragment; import android.view.Menu; import android.view.MenuItem; @@ -43,7 +42,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Set; -public class EncryptTextActivity extends EncryptActivity implements EncryptActivityInterface { +public class EncryptTextActivity extends EncryptActivity { /* Intents */ public static final String ACTION_ENCRYPT_TEXT = OpenKeychainIntents.ENCRYPT_TEXT; @@ -81,60 +80,38 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv return MODE_SYMMETRIC == mCurrentMode; } - @Override - public boolean isUseArmor() { - return true; - } - - @Override - public boolean isEncryptFilenames() { - return false; - } - - @Override public boolean isUseCompression() { return mUseCompression; } - @Override public boolean isHiddenRecipients() { return mHiddenRecipients; } - @Override public long getSignatureKey() { return mSigningKeyId; } - @Override public long[] getEncryptionKeys() { return mEncryptionKeyIds; } - @Override public String[] getEncryptionUsers() { return mEncryptionUserIds; } - @Override public void setSignatureKey(long signatureKey) { mSigningKeyId = signatureKey; - notifyUpdate(); } - @Override public void setEncryptionKeys(long[] encryptionKeys) { mEncryptionKeyIds = encryptionKeys; - notifyUpdate(); } - @Override public void setEncryptionUsers(String[] encryptionUsers) { mEncryptionUserIds = encryptionUsers; - notifyUpdate(); } - @Override public void setPassphrase(Passphrase passphrase) { if (mPassphrase != null) { mPassphrase.removeFromMemory(); @@ -142,50 +119,32 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv mPassphrase = passphrase; } - @Override public ArrayList getInputUris() { if (mInputUris == null) mInputUris = new ArrayList<>(); return mInputUris; } - @Override public ArrayList getOutputUris() { if (mOutputUris == null) mOutputUris = new ArrayList<>(); return mOutputUris; } - @Override public void setInputUris(ArrayList uris) { mInputUris = uris; - notifyUpdate(); } - @Override public void setOutputUris(ArrayList uris) { mOutputUris = uris; - notifyUpdate(); } - @Override public String getMessage() { return mMessage; } - @Override public void setMessage(String message) { mMessage = message; } - @Override - public void notifyUpdate() { - for (Fragment fragment : getSupportFragmentManager().getFragments()) { - if (fragment instanceof UpdateListener) { - ((UpdateListener) fragment).onNotifyUpdate(); - } - } - } - - @Override public void startEncrypt(boolean share) { mShareAfterEncrypt = share; startEncrypt(); @@ -348,7 +307,7 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv private void updateModeFragment() { getSupportFragmentManager().beginTransaction() - .replace(R.id.encrypt_pager_mode, + .replace(R.id.encrypt_mode, mCurrentMode == MODE_SYMMETRIC ? new EncryptSymmetricFragment() : new EncryptAsymmetricFragment() @@ -366,12 +325,10 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv case R.id.check_use_symmetric: { mCurrentMode = item.isChecked() ? MODE_SYMMETRIC : MODE_ASYMMETRIC; updateModeFragment(); - notifyUpdate(); break; } case R.id.check_enable_compression: { mUseCompression = item.isChecked(); - notifyUpdate(); break; } // case R.id.check_hidden_recipients: { -- cgit v1.2.3 From 13f4cc4ad32eb412e2ecdb649dcdd0788d30d5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 27 Mar 2015 00:40:37 +0100 Subject: Refactoring of EncryptTextActivity --- .../keychain/ui/EncryptActivity.java | 1 - .../keychain/ui/EncryptActivityInterface.java | 62 ---- .../keychain/ui/EncryptAsymmetricFragment.java | 196 ----------- .../keychain/ui/EncryptFilesActivity.java | 17 +- .../keychain/ui/EncryptFilesFragment.java | 16 +- .../keychain/ui/EncryptModeAsymmetricFragment.java | 196 +++++++++++ .../keychain/ui/EncryptModeSymmetricFragment.java | 106 ++++++ .../keychain/ui/EncryptSymmetricFragment.java | 106 ------ .../keychain/ui/EncryptTextActivity.java | 370 ++++----------------- .../keychain/ui/EncryptTextFragment.java | 337 ++++++++++++++++++- 10 files changed, 711 insertions(+), 696 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeSymmetricFragment.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 949a595d3..a1edf808c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -37,7 +37,6 @@ import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.util.Passphrase; - public abstract class EncryptActivity extends BaseActivity { public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java deleted file mode 100644 index 2a102c6c4..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * 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.net.Uri; - -import org.sufficientlysecure.keychain.util.Passphrase; - -import java.util.ArrayList; - -public interface EncryptActivityInterface { - - public interface UpdateListener { - void onNotifyUpdate(); - } - - public boolean isUseArmor(); - public boolean isUseCompression(); - public boolean isEncryptFilenames(); - public boolean isHiddenRecipients(); - - public long getSignatureKey(); - public long[] getEncryptionKeys(); - public String[] getEncryptionUsers(); - public void setSignatureKey(long signatureKey); - public void setEncryptionKeys(long[] encryptionKeys); - public void setEncryptionUsers(String[] encryptionUsers); - - public void setPassphrase(Passphrase passphrase); - - // ArrayList on purpose as only those are parcelable - public ArrayList getInputUris(); - public ArrayList getOutputUris(); - public void setInputUris(ArrayList uris); - public void setOutputUris(ArrayList uris); - - public String getMessage(); - public void setMessage(String message); - - /** - * Call this to notify the UI for changes done on the array lists or arrays, - * automatically called if setter is used - */ - public void notifyUpdate(); - - public void startEncrypt(boolean share); -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java deleted file mode 100644 index 06c711b92..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2014-2015 Dominik Schürmann - * - * 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.app.Activity; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.tokenautocomplete.TokenCompleteTextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView; -import org.sufficientlysecure.keychain.ui.widget.KeySpinner; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -public class EncryptAsymmetricFragment extends Fragment { - - public interface IAsymmetric { - - public void onSignatureKeyIdChanged(long signatureKeyId); - - public void onEncryptionKeyIdsChanged(long[] encryptionKeyIds); - - public void onEncryptionUserIdsChanged(String[] encryptionUserIds); - } - - ProviderHelper mProviderHelper; - - // view - private KeySpinner mSign; - private EncryptKeyCompletionView mEncryptKeyView; - - // model - private IAsymmetric mEncryptInterface; - -// @Override -// public void onNotifyUpdate() { -// if (mSign != null) { -// mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey()); -// } -// } - - public static final String ARG_SINGATURE_KEY_ID = "signature_key_id"; - public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids"; - - - /** - * Creates new instance of this fragment - */ - public static EncryptAsymmetricFragment newInstance(long signatureKey, long[] encryptionKeyIds) { - EncryptAsymmetricFragment frag = new EncryptAsymmetricFragment(); - - Bundle args = new Bundle(); - args.putLong(ARG_SINGATURE_KEY_ID, signatureKey); - args.putLongArray(ARG_ENCRYPTION_KEY_IDS, encryptionKeyIds); - frag.setArguments(args); - - return frag; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mEncryptInterface = (IAsymmetric) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement IAsymmetric"); - } - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false); - - mSign = (KeySpinner) view.findViewById(R.id.sign); - mSign.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() { - @Override - public void onKeyChanged(long masterKeyId) { - mEncryptInterface.onSignatureKeyIdChanged(masterKeyId); - } - }); - mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list); - mEncryptKeyView.setThreshold(1); // Start working from first character - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - mProviderHelper = new ProviderHelper(getActivity()); - - // preselect keys given - long signatureKeyId = getArguments().getLong(ARG_SINGATURE_KEY_ID); - long[] encryptionKeyIds = getArguments().getLongArray(ARG_ENCRYPTION_KEY_IDS); - preselectKeys(signatureKeyId, encryptionKeyIds); - - mEncryptKeyView.setTokenListener(new TokenCompleteTextView.TokenListener() { - @Override - public void onTokenAdded(Object token) { - if (token instanceof EncryptKeyCompletionView.EncryptionKey) { - updateEncryptionKeys(); - } - } - - @Override - public void onTokenRemoved(Object token) { - if (token instanceof EncryptKeyCompletionView.EncryptionKey) { - updateEncryptionKeys(); - } - } - }); - } - - /** - * If an Intent gives a signatureMasterKeyId and/or encryptionMasterKeyIds, preselect those! - */ - private void preselectKeys(long signatureKeyId, long[] encryptionKeyIds) { - if (signatureKeyId != Constants.key.none) { - try { - CachedPublicKeyRing keyring = mProviderHelper.getCachedPublicKeyRing( - KeyRings.buildUnifiedKeyRingUri(signatureKeyId)); - if (keyring.hasAnySecret()) { - mEncryptInterface.onSignatureKeyIdChanged(keyring.getMasterKeyId()); - mSign.setSelectedKeyId(signatureKeyId); - } - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - } - - if (encryptionKeyIds != null) { - for (long preselectedId : encryptionKeyIds) { - try { - CachedPublicKeyRing ring = mProviderHelper.getCachedPublicKeyRing( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(preselectedId)); - mEncryptKeyView.addObject(mEncryptKeyView.new EncryptionKey(ring)); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - } - // This is to work-around a rendering bug in TokenCompleteTextView - mEncryptKeyView.requestFocus(); - updateEncryptionKeys(); - } - } - - private void updateEncryptionKeys() { - List objects = mEncryptKeyView.getObjects(); - List keyIds = new ArrayList<>(); - List userIds = new ArrayList<>(); - for (Object object : objects) { - if (object instanceof EncryptKeyCompletionView.EncryptionKey) { - keyIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getKeyId()); - userIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getUserId()); - } - } - long[] keyIdsArr = new long[keyIds.size()]; - Iterator iterator = keyIds.iterator(); - for (int i = 0; i < keyIds.size(); i++) { - keyIdsArr[i] = iterator.next(); - } - mEncryptInterface.onEncryptionKeyIdsChanged(keyIdsArr); - mEncryptInterface.onEncryptionUserIdsChanged(userIds.toArray(new String[userIds.size()])); - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java index 269fdde8e..64e908b1a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -18,11 +18,13 @@ package org.sufficientlysecure.keychain.ui; +import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; +import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -33,7 +35,7 @@ import org.sufficientlysecure.keychain.util.Passphrase; import java.util.ArrayList; public class EncryptFilesActivity extends BaseActivity implements - EncryptAsymmetricFragment.IAsymmetric, EncryptSymmetricFragment.ISymmetric, + EncryptModeAsymmetricFragment.IAsymmetric, EncryptModeSymmetricFragment.ISymmetric, EncryptFilesFragment.IMode { /* Intents */ @@ -53,6 +55,13 @@ public class EncryptFilesActivity extends BaseActivity implements public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setFullScreenDialogClose(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }, false); + // Handle intent actions handleActions(getIntent(), savedInstanceState); } @@ -101,7 +110,7 @@ public class EncryptFilesActivity extends BaseActivity implements if (savedInstanceState == null) { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - mModeFragment = EncryptAsymmetricFragment.newInstance(mSigningKeyId, mEncryptionKeyIds); + mModeFragment = EncryptModeAsymmetricFragment.newInstance(mSigningKeyId, mEncryptionKeyIds); transaction.replace(R.id.encrypt_mode_container, mModeFragment, "mode"); mEncryptFragment = EncryptFilesFragment.newInstance(uris, useArmor); @@ -119,8 +128,8 @@ public class EncryptFilesActivity extends BaseActivity implements getSupportFragmentManager().beginTransaction() .replace(R.id.encrypt_mode_container, symmetric - ? EncryptSymmetricFragment.newInstance() - : EncryptAsymmetricFragment.newInstance(0, null) + ? EncryptModeSymmetricFragment.newInstance() + : EncryptModeAsymmetricFragment.newInstance(0, null) ) .commitAllowingStateLoss(); getSupportFragmentManager().executePendingTransactions(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 771800245..fb9a86b07 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -68,17 +68,18 @@ import java.util.Set; public class EncryptFilesFragment extends CryptoOperationFragment { - private static final int REQUEST_CODE_INPUT = 0x00007003; - private static final int REQUEST_CODE_OUTPUT = 0x00007007; - public interface IMode { - public void onModeChanged(boolean symmetric); } + public static final String ARG_USE_ASCII_ARMOR = "use_ascii_armor"; + public static final String ARG_URIS = "uris"; + + private static final int REQUEST_CODE_INPUT = 0x00007003; + private static final int REQUEST_CODE_OUTPUT = 0x00007007; + private IMode mModeInterface; - // model used by fragments private boolean mSymmetricMode = true; private boolean mUseArmor = false; private boolean mUseCompression = true; @@ -99,11 +100,6 @@ public class EncryptFilesFragment extends CryptoOperationFragment { private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter(); private final Map thumbnailCache = new HashMap<>(); - - public static final String ARG_USE_ASCII_ARMOR = "use_ascii_armor"; - public static final String ARG_URIS = "uris"; - - /** * Creates new instance of this fragment */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java new file mode 100644 index 000000000..8c117deca --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2014-2015 Dominik Schürmann + * + * 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.app.Activity; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.tokenautocomplete.TokenCompleteTextView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView; +import org.sufficientlysecure.keychain.ui.widget.KeySpinner; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class EncryptModeAsymmetricFragment extends Fragment { + + public interface IAsymmetric { + + public void onSignatureKeyIdChanged(long signatureKeyId); + + public void onEncryptionKeyIdsChanged(long[] encryptionKeyIds); + + public void onEncryptionUserIdsChanged(String[] encryptionUserIds); + } + + ProviderHelper mProviderHelper; + + // view + private KeySpinner mSign; + private EncryptKeyCompletionView mEncryptKeyView; + + // model + private IAsymmetric mEncryptInterface; + +// @Override +// public void onNotifyUpdate() { +// if (mSign != null) { +// mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey()); +// } +// } + + public static final String ARG_SINGATURE_KEY_ID = "signature_key_id"; + public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids"; + + + /** + * Creates new instance of this fragment + */ + public static EncryptModeAsymmetricFragment newInstance(long signatureKey, long[] encryptionKeyIds) { + EncryptModeAsymmetricFragment frag = new EncryptModeAsymmetricFragment(); + + Bundle args = new Bundle(); + args.putLong(ARG_SINGATURE_KEY_ID, signatureKey); + args.putLongArray(ARG_ENCRYPTION_KEY_IDS, encryptionKeyIds); + frag.setArguments(args); + + return frag; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mEncryptInterface = (IAsymmetric) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + " must implement IAsymmetric"); + } + } + + /** + * Inflate the layout for this fragment + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false); + + mSign = (KeySpinner) view.findViewById(R.id.sign); + mSign.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() { + @Override + public void onKeyChanged(long masterKeyId) { + mEncryptInterface.onSignatureKeyIdChanged(masterKeyId); + } + }); + mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list); + mEncryptKeyView.setThreshold(1); // Start working from first character + + return view; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + mProviderHelper = new ProviderHelper(getActivity()); + + // preselect keys given + long signatureKeyId = getArguments().getLong(ARG_SINGATURE_KEY_ID); + long[] encryptionKeyIds = getArguments().getLongArray(ARG_ENCRYPTION_KEY_IDS); + preselectKeys(signatureKeyId, encryptionKeyIds); + + mEncryptKeyView.setTokenListener(new TokenCompleteTextView.TokenListener() { + @Override + public void onTokenAdded(Object token) { + if (token instanceof EncryptKeyCompletionView.EncryptionKey) { + updateEncryptionKeys(); + } + } + + @Override + public void onTokenRemoved(Object token) { + if (token instanceof EncryptKeyCompletionView.EncryptionKey) { + updateEncryptionKeys(); + } + } + }); + } + + /** + * If an Intent gives a signatureMasterKeyId and/or encryptionMasterKeyIds, preselect those! + */ + private void preselectKeys(long signatureKeyId, long[] encryptionKeyIds) { + if (signatureKeyId != Constants.key.none) { + try { + CachedPublicKeyRing keyring = mProviderHelper.getCachedPublicKeyRing( + KeyRings.buildUnifiedKeyRingUri(signatureKeyId)); + if (keyring.hasAnySecret()) { + mEncryptInterface.onSignatureKeyIdChanged(keyring.getMasterKeyId()); + mSign.setSelectedKeyId(signatureKeyId); + } + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + } + + if (encryptionKeyIds != null) { + for (long preselectedId : encryptionKeyIds) { + try { + CachedPublicKeyRing ring = mProviderHelper.getCachedPublicKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(preselectedId)); + mEncryptKeyView.addObject(mEncryptKeyView.new EncryptionKey(ring)); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + } + // This is to work-around a rendering bug in TokenCompleteTextView + mEncryptKeyView.requestFocus(); + updateEncryptionKeys(); + } + } + + private void updateEncryptionKeys() { + List objects = mEncryptKeyView.getObjects(); + List keyIds = new ArrayList<>(); + List userIds = new ArrayList<>(); + for (Object object : objects) { + if (object instanceof EncryptKeyCompletionView.EncryptionKey) { + keyIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getKeyId()); + userIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getUserId()); + } + } + long[] keyIdsArr = new long[keyIds.size()]; + Iterator iterator = keyIds.iterator(); + for (int i = 0; i < keyIds.size(); i++) { + keyIdsArr[i] = iterator.next(); + } + mEncryptInterface.onEncryptionKeyIdsChanged(keyIdsArr); + mEncryptInterface.onEncryptionUserIdsChanged(userIds.toArray(new String[userIds.size()])); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeSymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeSymmetricFragment.java new file mode 100644 index 000000000..48b1f4983 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeSymmetricFragment.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2014-2015 Dominik Schürmann + * + * 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.app.Activity; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Passphrase; + +public class EncryptModeSymmetricFragment extends Fragment { + + public interface ISymmetric { + + public void onPassphraseChanged(Passphrase passphrase); + } + + private ISymmetric mEncryptInterface; + + private EditText mPassphrase; + private EditText mPassphraseAgain; + + /** + * Creates new instance of this fragment + */ + public static EncryptModeSymmetricFragment newInstance() { + EncryptModeSymmetricFragment frag = new EncryptModeSymmetricFragment(); + + Bundle args = new Bundle(); + frag.setArguments(args); + + return frag; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mEncryptInterface = (ISymmetric) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + " must implement ISymmetric"); + } + } + + /** + * Inflate the layout for this fragment + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.encrypt_symmetric_fragment, container, false); + + mPassphrase = (EditText) view.findViewById(R.id.passphrase); + mPassphraseAgain = (EditText) view.findViewById(R.id.passphraseAgain); + TextWatcher textWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + // update passphrase in EncryptActivity + Passphrase p1 = new Passphrase(mPassphrase.getText()); + Passphrase p2 = new Passphrase(mPassphraseAgain.getText()); + boolean passesEquals = (p1.equals(p2)); + p1.removeFromMemory(); + p2.removeFromMemory(); + if (passesEquals) { + mEncryptInterface.onPassphraseChanged(new Passphrase(mPassphrase.getText())); + } else { + mEncryptInterface.onPassphraseChanged(null); + } + } + }; + mPassphrase.addTextChangedListener(textWatcher); + mPassphraseAgain.addTextChangedListener(textWatcher); + + return view; + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java deleted file mode 100644 index 22e116a42..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2014-2015 Dominik Schürmann - * - * 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.app.Activity; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.EditText; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Passphrase; - -public class EncryptSymmetricFragment extends Fragment { - - public interface ISymmetric { - - public void onPassphraseChanged(Passphrase passphrase); - } - - private ISymmetric mEncryptInterface; - - private EditText mPassphrase; - private EditText mPassphraseAgain; - - /** - * Creates new instance of this fragment - */ - public static EncryptSymmetricFragment newInstance() { - EncryptSymmetricFragment frag = new EncryptSymmetricFragment(); - - Bundle args = new Bundle(); - frag.setArguments(args); - - return frag; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mEncryptInterface = (ISymmetric) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement ISymmetric"); - } - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.encrypt_symmetric_fragment, container, false); - - mPassphrase = (EditText) view.findViewById(R.id.passphrase); - mPassphraseAgain = (EditText) view.findViewById(R.id.passphraseAgain); - TextWatcher textWatcher = new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - @Override - public void afterTextChanged(Editable s) { - // update passphrase in EncryptActivity - Passphrase p1 = new Passphrase(mPassphrase.getText()); - Passphrase p2 = new Passphrase(mPassphraseAgain.getText()); - boolean passesEquals = (p1.equals(p2)); - p1.removeFromMemory(); - p2.removeFromMemory(); - if (passesEquals) { - mEncryptInterface.onPassphraseChanged(new Passphrase(mPassphrase.getText())); - } else { - mEncryptInterface.onPassphraseChanged(null); - } - } - }; - mPassphrase.addTextChangedListener(textWatcher); - mPassphraseAgain.addTextChangedListener(textWatcher); - - return view; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 56f0b198e..2ffb29b09 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2012-2015 Dominik Schürmann * Copyright (C) 2010-2014 Thialfihar * * This program is free software: you can redistribute it and/or modify @@ -19,30 +19,21 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; -import android.net.Uri; import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.view.View; -import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.api.OpenKeychainIntents; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; -import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.PgpConstants; -import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; -import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.base.BaseActivity; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; -import org.sufficientlysecure.keychain.util.ShareHelper; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; - -public class EncryptTextActivity extends EncryptActivity { +public class EncryptTextActivity extends BaseActivity implements + EncryptModeAsymmetricFragment.IAsymmetric, EncryptModeSymmetricFragment.ISymmetric, + EncryptTextFragment.IMode { /* Intents */ public static final String ACTION_ENCRYPT_TEXT = OpenKeychainIntents.ENCRYPT_TEXT; @@ -54,244 +45,22 @@ public class EncryptTextActivity extends EncryptActivity { public static final String EXTRA_SIGNATURE_KEY_ID = Constants.EXTRA_PREFIX + "EXTRA_SIGNATURE_KEY_ID"; public static final String EXTRA_ENCRYPTION_KEY_IDS = Constants.EXTRA_PREFIX + "EXTRA_SIGNATURE_KEY_IDS"; - // view - private int mCurrentMode = MODE_ASYMMETRIC; - - // tabs - private static final int MODE_ASYMMETRIC = 0; - private static final int MODE_SYMMETRIC = 1; - - // model used by fragments - private boolean mShareAfterEncrypt = false; - private boolean mUseCompression = true; - private boolean mHiddenRecipients = false; - - private long mEncryptionKeyIds[] = null; - private String mEncryptionUserIds[] = null; - // TODO Constants.key.none? What's wrong with a null value? - private long mSigningKeyId = Constants.key.none; - private Passphrase mPassphrase = new Passphrase(); - - private ArrayList mInputUris; - private ArrayList mOutputUris; - private String mMessage = ""; - - public boolean isModeSymmetric() { - return MODE_SYMMETRIC == mCurrentMode; - } - - public boolean isUseCompression() { - return mUseCompression; - } - - public boolean isHiddenRecipients() { - return mHiddenRecipients; - } - - public long getSignatureKey() { - return mSigningKeyId; - } - - public long[] getEncryptionKeys() { - return mEncryptionKeyIds; - } - - public String[] getEncryptionUsers() { - return mEncryptionUserIds; - } - - public void setSignatureKey(long signatureKey) { - mSigningKeyId = signatureKey; - } - - public void setEncryptionKeys(long[] encryptionKeys) { - mEncryptionKeyIds = encryptionKeys; - } - - public void setEncryptionUsers(String[] encryptionUsers) { - mEncryptionUserIds = encryptionUsers; - } - - public void setPassphrase(Passphrase passphrase) { - if (mPassphrase != null) { - mPassphrase.removeFromMemory(); - } - mPassphrase = passphrase; - } - - public ArrayList getInputUris() { - if (mInputUris == null) mInputUris = new ArrayList<>(); - return mInputUris; - } - - public ArrayList getOutputUris() { - if (mOutputUris == null) mOutputUris = new ArrayList<>(); - return mOutputUris; - } - - public void setInputUris(ArrayList uris) { - mInputUris = uris; - } - - public void setOutputUris(ArrayList uris) { - mOutputUris = uris; - } - - public String getMessage() { - return mMessage; - } - - public void setMessage(String message) { - mMessage = message; - } - - public void startEncrypt(boolean share) { - mShareAfterEncrypt = share; - startEncrypt(); - } - - @Override - protected void onEncryptSuccess(SignEncryptResult result) { - if (mShareAfterEncrypt) { - // Share encrypted message/file - startActivity(sendWithChooserExcludingEncrypt(result.getResultBytes())); - } else { - // Copy to clipboard - copyToClipboard(result.getResultBytes()); - result.createNotify(EncryptTextActivity.this).show(); - // Notify.create(EncryptTextActivity.this, - // R.string.encrypt_sign_clipboard_successful, Notify.Style.OK) - // .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); - } - } - - @Override - protected SignEncryptParcel createEncryptBundle() { - // fill values for this action - SignEncryptParcel data = new SignEncryptParcel(); - - data.setBytes(mMessage.getBytes()); - data.setCleartextSignature(true); - - if (mUseCompression) { - data.setCompressionId(PgpConstants.sPreferredCompressionAlgorithms.get(0)); - } else { - data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED); - } - data.setHiddenRecipients(mHiddenRecipients); - data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); - data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); - - // Always use armor for messages - data.setEnableAsciiArmorOutput(true); - - if (isModeSymmetric()) { - Log.d(Constants.TAG, "Symmetric encryption enabled!"); - Passphrase passphrase = mPassphrase; - if (passphrase.isEmpty()) { - passphrase = null; - } - data.setSymmetricPassphrase(passphrase); - } else { - data.setEncryptionMasterKeyIds(mEncryptionKeyIds); - data.setSignatureMasterKeyId(mSigningKeyId); - data.setSignaturePassphrase(mSigningKeyPassphrase); - } - return data; - } - - private void copyToClipboard(byte[] resultBytes) { - ClipboardReflection.copyToClipboard(this, new String(resultBytes)); - } - - /** - * Create Intent Chooser but exclude OK's EncryptActivity. - */ - private Intent sendWithChooserExcludingEncrypt(byte[] resultBytes) { - Intent prototype = createSendIntent(resultBytes); - String title = getString(R.string.title_share_message); - - // we don't want to encrypt the encrypted, no inception ;) - String[] blacklist = new String[]{ - Constants.PACKAGE_NAME + ".ui.EncryptTextActivity", - "org.thialfihar.android.apg.ui.EncryptActivity" - }; - - return new ShareHelper(this).createChooserExcluding(prototype, title, blacklist); - } - - private Intent createSendIntent(byte[] resultBytes) { - Intent sendIntent; - sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.setType(Constants.ENCRYPTED_TEXT_MIME); - sendIntent.putExtra(Intent.EXTRA_TEXT, new String(resultBytes)); - - if (!isModeSymmetric() && mEncryptionUserIds != null) { - Set users = new HashSet<>(); - for (String user : mEncryptionUserIds) { - KeyRing.UserId userId = KeyRing.splitUserId(user); - if (userId.email != null) { - users.add(userId.email); - } - } - // pass trough email addresses as extra for email applications - sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()])); - } - return sendIntent; - } - - protected boolean inputIsValid() { - if (mMessage == null) { - Notify.create(this, R.string.error_message, Notify.Style.ERROR) - .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); - return false; - } - - if (isModeSymmetric()) { - // symmetric encryption checks - - if (mPassphrase == null) { - Notify.create(this, R.string.passphrases_do_not_match, Notify.Style.ERROR) - .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); - return false; - } - if (mPassphrase.isEmpty()) { - Notify.create(this, R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) - .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); - return false; - } - - } else { - // asymmetric encryption checks - - boolean gotEncryptionKeys = (mEncryptionKeyIds != null - && mEncryptionKeyIds.length > 0); - - if (!gotEncryptionKeys && mSigningKeyId == 0) { - Notify.create(this, R.string.select_encryption_or_signature_key, Notify.Style.ERROR) - .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); - return false; - } - } - return true; - } + Fragment mModeFragment; + EncryptTextFragment mEncryptFragment; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // if called with an intent action, do not init drawer navigation - if (ACTION_ENCRYPT_TEXT.equals(getIntent().getAction())) { - // lock drawer -// deactivateDrawerNavigation(); - // TODO: back button to key? - } else { -// activateDrawerNavigation(savedInstanceState); - } + setFullScreenDialogClose(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }, false); // Handle intent actions - handleActions(getIntent()); - updateModeFragment(); + handleActions(getIntent(), savedInstanceState); } @Override @@ -299,56 +68,13 @@ public class EncryptTextActivity extends EncryptActivity { setContentView(R.layout.encrypt_text_activity); } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.encrypt_text_activity, menu); - return super.onCreateOptionsMenu(menu); - } - - private void updateModeFragment() { - getSupportFragmentManager().beginTransaction() - .replace(R.id.encrypt_mode, - mCurrentMode == MODE_SYMMETRIC - ? new EncryptSymmetricFragment() - : new EncryptAsymmetricFragment() - ) - .commitAllowingStateLoss(); - getSupportFragmentManager().executePendingTransactions(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.isCheckable()) { - item.setChecked(!item.isChecked()); - } - switch (item.getItemId()) { - case R.id.check_use_symmetric: { - mCurrentMode = item.isChecked() ? MODE_SYMMETRIC : MODE_ASYMMETRIC; - updateModeFragment(); - break; - } - case R.id.check_enable_compression: { - mUseCompression = item.isChecked(); - break; - } -// case R.id.check_hidden_recipients: { -// mHiddenRecipients = item.isChecked(); -// notifyUpdate(); -// break; -// } - default: { - return super.onOptionsItemSelected(item); - } - } - return true; - } /** * Handles all actions with this intent * * @param intent */ - private void handleActions(Intent intent) { + private void handleActions(Intent intent, Bundle savedInstanceState) { String action = intent.getAction(); Bundle extras = intent.getExtras(); String type = intent.getType(); @@ -379,19 +105,61 @@ public class EncryptTextActivity extends EncryptActivity { } String textData = extras.getString(EXTRA_TEXT); + if (ACTION_ENCRYPT_TEXT.equals(action) && textData == null) { + Log.e(Constants.TAG, "Include the extra 'text' in your Intent!"); + return; + } // preselect keys given by intent - mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID); - mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS); + long mSigningKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID); + long[] mEncryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS); - /** - * Main Actions - */ - if (ACTION_ENCRYPT_TEXT.equals(action) && textData != null) { - mMessage = textData; - } else if (ACTION_ENCRYPT_TEXT.equals(action)) { - Log.e(Constants.TAG, "Include the extra 'text' in your Intent!"); + + if (savedInstanceState == null) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + + mModeFragment = EncryptModeAsymmetricFragment.newInstance(mSigningKeyId, mEncryptionKeyIds); + transaction.replace(R.id.encrypt_mode_container, mModeFragment, "mode"); + + mEncryptFragment = EncryptTextFragment.newInstance(textData); + transaction.replace(R.id.encrypt_text_container, mEncryptFragment, "text"); + + transaction.commit(); + + getSupportFragmentManager().executePendingTransactions(); } } + @Override + public void onModeChanged(boolean symmetric) { + // switch fragments + getSupportFragmentManager().beginTransaction() + .replace(R.id.encrypt_mode_container, + symmetric + ? EncryptModeSymmetricFragment.newInstance() + : EncryptModeAsymmetricFragment.newInstance(0, null) + ) + .commitAllowingStateLoss(); + getSupportFragmentManager().executePendingTransactions(); + } + + @Override + public void onSignatureKeyIdChanged(long signatureKeyId) { + mEncryptFragment.setSigningKeyId(signatureKeyId); + } + + @Override + public void onEncryptionKeyIdsChanged(long[] encryptionKeyIds) { + mEncryptFragment.setEncryptionKeyIds(encryptionKeyIds); + } + + @Override + public void onEncryptionUserIdsChanged(String[] encryptionUserIds) { + mEncryptFragment.setEncryptionUserIds(encryptionUserIds); + } + + @Override + public void onPassphraseChanged(Passphrase passphrase) { + mEncryptFragment.setPassphrase(passphrase); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index 5d9994c5c..c71edcd22 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Dominik Schürmann + * Copyright (C) 2014-2015 Dominik Schürmann * * 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 @@ -18,32 +18,102 @@ package org.sufficientlysecure.keychain.ui; import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.Fragment; +import android.os.Message; +import android.os.Messenger; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import org.spongycastle.bcpg.CompressionAlgorithmTags; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; +import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; +import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.PgpConstants; +import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Passphrase; +import org.sufficientlysecure.keychain.util.ShareHelper; + +import java.util.HashSet; +import java.util.Set; + +public class EncryptTextFragment extends CryptoOperationFragment { + + public interface IMode { + public void onModeChanged(boolean symmetric); + } -public class EncryptTextFragment extends Fragment { public static final String ARG_TEXT = "text"; + private IMode mModeInterface; + + private boolean mSymmetricMode = true; + private boolean mShareAfterEncrypt = false; + private boolean mUseCompression = true; + private boolean mHiddenRecipients = false; + + private long mEncryptionKeyIds[] = null; + private String mEncryptionUserIds[] = null; + // TODO Constants.key.none? What's wrong with a null value? + private long mSigningKeyId = Constants.key.none; + private Passphrase mPassphrase = new Passphrase(); + private String mMessage = ""; + private TextView mText; - private EncryptActivityInterface mEncryptInterface; + public void setEncryptionKeyIds(long[] encryptionKeyIds) { + mEncryptionKeyIds = encryptionKeyIds; + } + + public void setEncryptionUserIds(String[] encryptionUserIds) { + mEncryptionUserIds = encryptionUserIds; + } + + public void setSigningKeyId(long signingKeyId) { + mSigningKeyId = signingKeyId; + } + + public void setPassphrase(Passphrase passphrase) { + mPassphrase = passphrase; + } + + /** + * Creates new instance of this fragment + */ + public static EncryptTextFragment newInstance(String text) { + EncryptTextFragment frag = new EncryptTextFragment(); + + Bundle args = new Bundle(); + args.putString(ARG_TEXT, text); + frag.setArguments(args); + + return frag; + } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { - mEncryptInterface = (EncryptActivityInterface) activity; + mModeInterface = (IMode) activity; } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface"); + throw new ClassCastException(activity.toString() + " must implement IMode"); } } @@ -54,6 +124,9 @@ public class EncryptTextFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.encrypt_text_fragment, container, false); + if (mMessage != null) { + mText.setText(mMessage); + } mText = (TextView) view.findViewById(R.id.encrypt_text_text); mText.addTextChangedListener(new TextWatcher() { @Override @@ -68,7 +141,7 @@ public class EncryptTextFragment extends Fragment { @Override public void afterTextChanged(Editable s) { - mEncryptInterface.setMessage(s.toString()); + mMessage = s.toString(); } }); @@ -78,29 +151,43 @@ public class EncryptTextFragment extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mMessage = getArguments().getString(ARG_TEXT); setHasOptionsMenu(true); } @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - String text = mEncryptInterface.getMessage(); - if (text != null) { - mText.setText(text); - } + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.encrypt_text_activity, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { + if (item.isCheckable()) { + item.setChecked(!item.isChecked()); + } switch (item.getItemId()) { + case R.id.check_use_symmetric: { + mSymmetricMode = item.isChecked(); + mModeInterface.onModeChanged(mSymmetricMode); + break; + } + case R.id.check_enable_compression: { + mUseCompression = item.isChecked(); + break; + } +// case R.id.check_hidden_recipients: { +// mHiddenRecipients = item.isChecked(); +// notifyUpdate(); +// break; +// } case R.id.encrypt_copy: { - mEncryptInterface.startEncrypt(false); + startEncrypt(false); break; } case R.id.encrypt_share: { - mEncryptInterface.startEncrypt(true); + startEncrypt(true); break; } default: { @@ -109,4 +196,222 @@ public class EncryptTextFragment extends Fragment { } return true; } + + + protected void onEncryptSuccess(SignEncryptResult result) { + if (mShareAfterEncrypt) { + // Share encrypted message/file + startActivity(sendWithChooserExcludingEncrypt(result.getResultBytes())); + } else { + // Copy to clipboard + copyToClipboard(result.getResultBytes()); + result.createNotify(getActivity()).show(); + // Notify.create(EncryptTextActivity.this, + // R.string.encrypt_sign_clipboard_successful, Notify.Style.OK) + // .show(getSupportFragmentManager().findFragmentById(R.id.encrypt_text_fragment)); + } + } + + protected SignEncryptParcel createEncryptBundle() { + // fill values for this action + SignEncryptParcel data = new SignEncryptParcel(); + + data.setBytes(mMessage.getBytes()); + data.setCleartextSignature(true); + + if (mUseCompression) { + data.setCompressionId(PgpConstants.sPreferredCompressionAlgorithms.get(0)); + } else { + data.setCompressionId(CompressionAlgorithmTags.UNCOMPRESSED); + } + data.setHiddenRecipients(mHiddenRecipients); + data.setSymmetricEncryptionAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); + data.setSignatureHashAlgorithm(PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED); + + // Always use armor for messages + data.setEnableAsciiArmorOutput(true); + + if (mSymmetricMode) { + Log.d(Constants.TAG, "Symmetric encryption enabled!"); + Passphrase passphrase = mPassphrase; + if (passphrase.isEmpty()) { + passphrase = null; + } + data.setSymmetricPassphrase(passphrase); + } else { + data.setEncryptionMasterKeyIds(mEncryptionKeyIds); + data.setSignatureMasterKeyId(mSigningKeyId); +// data.setSignaturePassphrase(mSigningKeyPassphrase); + } + return data; + } + + private void copyToClipboard(byte[] resultBytes) { + ClipboardReflection.copyToClipboard(getActivity(), new String(resultBytes)); + } + + /** + * Create Intent Chooser but exclude OK's EncryptActivity. + */ + private Intent sendWithChooserExcludingEncrypt(byte[] resultBytes) { + Intent prototype = createSendIntent(resultBytes); + String title = getString(R.string.title_share_message); + + // we don't want to encrypt the encrypted, no inception ;) + String[] blacklist = new String[]{ + Constants.PACKAGE_NAME + ".ui.EncryptTextActivity", + "org.thialfihar.android.apg.ui.EncryptActivity" + }; + + return new ShareHelper(getActivity()).createChooserExcluding(prototype, title, blacklist); + } + + private Intent createSendIntent(byte[] resultBytes) { + Intent sendIntent; + sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.setType(Constants.ENCRYPTED_TEXT_MIME); + sendIntent.putExtra(Intent.EXTRA_TEXT, new String(resultBytes)); + + if (!mSymmetricMode && mEncryptionUserIds != null) { + Set users = new HashSet<>(); + for (String user : mEncryptionUserIds) { + KeyRing.UserId userId = KeyRing.splitUserId(user); + if (userId.email != null) { + users.add(userId.email); + } + } + // pass trough email addresses as extra for email applications + sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()])); + } + return sendIntent; + } + + protected boolean inputIsValid() { + if (mMessage == null) { + Notify.create(getActivity(), R.string.error_message, Notify.Style.ERROR) + .show(this); + return false; + } + + if (mSymmetricMode) { + // symmetric encryption checks + + if (mPassphrase == null) { + Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR) + .show(this); + return false; + } + if (mPassphrase.isEmpty()) { + Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) + .show(this); + return false; + } + + } else { + // asymmetric encryption checks + + boolean gotEncryptionKeys = (mEncryptionKeyIds != null + && mEncryptionKeyIds.length > 0); + + if (!gotEncryptionKeys && mSigningKeyId == 0) { + Notify.create(getActivity(), R.string.select_encryption_or_signature_key, Notify.Style.ERROR) + .show(this); + return false; + } + } + return true; + } + + + public void startEncrypt(boolean share) { + mShareAfterEncrypt = share; + startEncrypt(); + } + + public void startEncrypt() { + cryptoOperation(null); + } + + @Override + protected void cryptoOperation(CryptoInputParcel cryptoInput) { + if (!inputIsValid()) { + // Notify was created by inputIsValid. + return; + } + + // Send all information needed to service to edit key in other thread + Intent intent = new Intent(getActivity(), KeychainIntentService.class); + intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); + + final SignEncryptParcel input = createEncryptBundle(); + if (cryptoInput != null) { + input.setCryptoInput(cryptoInput); + } + + Bundle data = new Bundle(); + data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Message is received after encrypting is done in KeychainIntentService + ServiceProgressHandler serviceHandler = new ServiceProgressHandler( + getActivity(), + getString(R.string.progress_encrypting), + ProgressDialog.STYLE_HORIZONTAL, + ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + // handle pending messages + if (handlePendingMessage(message)) { + return; + } + + if (message.arg1 == MessageStatus.OKAY.ordinal()) { + SignEncryptResult result = + message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); + + PgpSignEncryptResult pgpResult = result.getPending(); + +// if (pgpResult != null && pgpResult.isPending()) { +// if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == +// PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { +// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); +// } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == +// PgpSignEncryptResult.RESULT_PENDING_NFC) { +// +// RequiredInputParcel parcel = RequiredInputParcel.createNfcSignOperation( +// pgpResult.getNfcHash(), +// pgpResult.getNfcAlgo(), +// input.getSignatureTime()); +// startNfcSign(pgpResult.getNfcKeyId(), parcel); +// +// } else { +// throw new RuntimeException("Unhandled pending result!"); +// } +// return; +// } + + if (result.success()) { + onEncryptSuccess(result); + } else { + result.createNotify(getActivity()).show(); + } + + // no matter the result, reset parameters +// mSigningKeyPassphrase = null; + } + } + }; + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(serviceHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // show progress dialog + serviceHandler.showProgressDialog(getActivity()); + + // start service with intent + getActivity().startService(intent); + } + } -- cgit v1.2.3 From b82f273284b90d8ab41c806cc2858865d33b2390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 27 Mar 2015 00:55:55 +0100 Subject: Start reworking decrypt ui classes --- .../keychain/ui/DecryptFilesFragment.java | 223 +++++++++++---------- .../keychain/ui/DecryptFragment.java | 47 ++--- .../keychain/ui/DecryptTextFragment.java | 99 +++++---- 3 files changed, 197 insertions(+), 172 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java index c75e28145..ecc99b348 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java @@ -39,6 +39,7 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentService.IOType; import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.util.Notify; @@ -144,7 +145,7 @@ public class DecryptFilesFragment extends DecryptFragment { return; } - decryptOriginalFilename(); +// decryptOriginalFilename(); } private String removeEncryptedAppend(String name) { @@ -174,82 +175,93 @@ public class DecryptFilesFragment extends DecryptFragment { } } - private void decryptOriginalFilename() { - Log.d(Constants.TAG, "decryptOriginalFilename"); - Intent intent = new Intent(getActivity(), KeychainIntentService.class); - - // fill values for this action - Bundle data = new Bundle(); - intent.setAction(KeychainIntentService.ACTION_DECRYPT_METADATA); - - // data - Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri); - - data.putInt(KeychainIntentService.SOURCE, IOType.URI.ordinal()); - data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_INPUT_URI, mInputUri); - - data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal()); - data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri); - - data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); - data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after decrypting is done in KeychainIntentService - ServiceProgressHandler saveHandler = new ServiceProgressHandler( - getActivity(), - getString(R.string.progress_decrypting), - ProgressDialog.STYLE_HORIZONTAL, - ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == MessageStatus.OKAY.ordinal()) { - // get returned data bundle - Bundle returnData = message.getData(); - - DecryptVerifyResult pgpResult = - returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); - - if (pgpResult.isPending()) { - if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == - DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { - startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == - DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { - startPassphraseDialog(Constants.key.symmetric); - } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == - DecryptVerifyResult.RESULT_PENDING_NFC) { - startNfcDecrypt(pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); - } else { - throw new RuntimeException("Unhandled pending result!"); - } - } else if (pgpResult.success()) { - // go on... - askForOutputFilename(pgpResult.getDecryptMetadata().getFilename()); - } else { - pgpResult.createNotify(getActivity()).show(); - } - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - saveHandler.showProgressDialog(getActivity()); - - // start service with intent - getActivity().startService(intent); + // TODO: also needs to use cryptoOperation!!! (switch between this and normal decrypt +// private void decryptOriginalFilename() { +// Log.d(Constants.TAG, "decryptOriginalFilename"); +// +// Intent intent = new Intent(getActivity(), KeychainIntentService.class); +// +// // fill values for this action +// Bundle data = new Bundle(); +// intent.setAction(KeychainIntentService.ACTION_DECRYPT_METADATA); +// +// // data +// Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri); +// +// data.putInt(KeychainIntentService.SOURCE, IOType.URI.ordinal()); +// data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_INPUT_URI, mInputUri); +// +// data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal()); +// data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri); +// +// data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); +// data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); +// +// intent.putExtra(KeychainIntentService.EXTRA_DATA, data); +// +// // Message is received after decrypting is done in KeychainIntentService +// ServiceProgressHandler saveHandler = new ServiceProgressHandler( +// getActivity(), +// getString(R.string.progress_decrypting), +// ProgressDialog.STYLE_HORIZONTAL, +// ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) { +// public void handleMessage(Message message) { +// // handle messages by standard KeychainIntentServiceHandler first +// super.handleMessage(message); +// +// // handle pending messages +// if (handlePendingMessage(message)) { +// return; +// } +// +// if (message.arg1 == MessageStatus.OKAY.ordinal()) { +// // get returned data bundle +// Bundle returnData = message.getData(); +// +// DecryptVerifyResult pgpResult = +// returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); +// +// if (pgpResult.isPending()) { +// if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == +// DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { +// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); +// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == +// DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { +// startPassphraseDialog(Constants.key.symmetric); +// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == +// DecryptVerifyResult.RESULT_PENDING_NFC) { +// startNfcDecrypt(pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); +// } else { +// throw new RuntimeException("Unhandled pending result!"); +// } +// } else if (pgpResult.success()) { +// // go on... +// askForOutputFilename(pgpResult.getDecryptMetadata().getFilename()); +// } else { +// pgpResult.createNotify(getActivity()).show(); +// } +// } +// } +// }; +// +// // Create a new Messenger for the communication back +// Messenger messenger = new Messenger(saveHandler); +// intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); +// +// // show progress dialog +// saveHandler.showProgressDialog(getActivity()); +// +// // start service with intent +// getActivity().startService(intent); +// } + + private void decryptStart() { + cryptoOperation(new CryptoInputParcel()); } @Override - protected void decryptStart() { + protected void cryptoOperation(CryptoInputParcel cryptoInput) { Log.d(Constants.TAG, "decryptStart"); // Send all information needed to service to decrypt in other thread @@ -284,6 +296,11 @@ public class DecryptFilesFragment extends DecryptFragment { // handle messages by standard KeychainIntentServiceHandler first super.handleMessage(message); + // handle pending messages + if (handlePendingMessage(message)) { + return; + } + if (message.arg1 == MessageStatus.OKAY.ordinal()) { // get returned data bundle Bundle returnData = message.getData(); @@ -291,20 +308,21 @@ public class DecryptFilesFragment extends DecryptFragment { DecryptVerifyResult pgpResult = returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); - if (pgpResult.isPending()) { - if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == - DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { - startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == - DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { - startPassphraseDialog(Constants.key.symmetric); - } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == - DecryptVerifyResult.RESULT_PENDING_NFC) { - startNfcDecrypt(pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); - } else { - throw new RuntimeException("Unhandled pending result!"); - } - } else if (pgpResult.success()) { +// if (pgpResult.isPending()) { +// if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == +// DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { +// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); +// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == +// DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { +// startPassphraseDialog(Constants.key.symmetric); +// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == +// DecryptVerifyResult.RESULT_PENDING_NFC) { +// startNfcDecrypt(pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); +// } else { +// throw new RuntimeException("Unhandled pending result!"); +// } + + if (pgpResult.success()) { // display signature result in activity onResult(pgpResult); @@ -346,21 +364,21 @@ public class DecryptFilesFragment extends DecryptFragment { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { - case REQUEST_CODE_PASSPHRASE: { - if (resultCode == Activity.RESULT_OK && data != null) { - mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); - decryptOriginalFilename(); - } - return; - } - - case REQUEST_CODE_NFC_DECRYPT: { - if (resultCode == Activity.RESULT_OK && data != null) { - mNfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); - decryptOriginalFilename(); - } - return; - } +// case REQUEST_CODE_PASSPHRASE: { +// if (resultCode == Activity.RESULT_OK && data != null) { +// mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); +//// decryptOriginalFilename(); +// } +// return; +// } +// +// case REQUEST_CODE_NFC_DECRYPT: { +// if (resultCode == Activity.RESULT_OK && data != null) { +// mNfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); +//// decryptOriginalFilename(); +// } +// return; +// } case REQUEST_CODE_INPUT: { if (resultCode == Activity.RESULT_OK && data != null) { @@ -383,4 +401,5 @@ public class DecryptFilesFragment extends DecryptFragment { } } } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index 63508e530..f00136d5b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -34,11 +34,11 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; import org.sufficientlysecure.keychain.util.Passphrase; -public abstract class DecryptFragment extends Fragment { +public abstract class DecryptFragment extends CryptoOperationFragment { private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006; - public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; - public static final int REQUEST_CODE_NFC_DECRYPT = 0x00008002; +// public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; +// public static final int REQUEST_CODE_NFC_DECRYPT = 0x00008002; protected long mSignatureKeyId = 0; @@ -95,24 +95,24 @@ public abstract class DecryptFragment extends Fragment { startActivity(viewKeyIntent); } - protected void startPassphraseDialog(long subkeyId) { - Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); - intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId); - startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); - } - - protected void startNfcDecrypt(long subKeyId, Passphrase pin, byte[] encryptedSessionKey) { - // build PendingIntent for Yubikey NFC operations - Intent intent = new Intent(getActivity(), NfcActivity.class); - intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY); - intent.putExtra(NfcActivity.EXTRA_DATA, new Intent()); // not used, only relevant to OpenPgpService - intent.putExtra(NfcActivity.EXTRA_KEY_ID, subKeyId); - intent.putExtra(NfcActivity.EXTRA_PIN, pin); - - intent.putExtra(NfcActivity.EXTRA_NFC_ENC_SESSION_KEY, encryptedSessionKey); - - startActivityForResult(intent, REQUEST_CODE_NFC_DECRYPT); - } +// protected void startPassphraseDialog(long subkeyId) { +// Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); +// intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId); +// startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); +// } +// +// protected void startNfcDecrypt(long subKeyId, Passphrase pin, byte[] encryptedSessionKey) { +// // build PendingIntent for Yubikey NFC operations +// Intent intent = new Intent(getActivity(), NfcActivity.class); +// intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY); +// intent.putExtra(NfcActivity.EXTRA_DATA, new Intent()); // not used, only relevant to OpenPgpService +// intent.putExtra(NfcActivity.EXTRA_KEY_ID, subKeyId); +// intent.putExtra(NfcActivity.EXTRA_PIN, pin); +// +// intent.putExtra(NfcActivity.EXTRA_NFC_ENC_SESSION_KEY, encryptedSessionKey); +// +// startActivityForResult(intent, REQUEST_CODE_NFC_DECRYPT); +// } /** * @@ -253,9 +253,4 @@ public abstract class DecryptFragment extends Fragment { }); } - /** - * Should be overridden by MessageFragment and FileFragment to start actual decryption - */ - protected abstract void decryptStart(); - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index f6e21937d..523b24fd7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentService.IOType; import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; @@ -147,8 +148,13 @@ public class DecryptTextFragment extends DecryptFragment { } } + private void decryptStart() { + cryptoOperation(new CryptoInputParcel()); + } + @Override - protected void decryptStart() { + protected void cryptoOperation(CryptoInputParcel cryptoInput) { + Log.d(Constants.TAG, "decryptStart"); // Send all information needed to service to decrypt in other thread @@ -177,6 +183,11 @@ public class DecryptTextFragment extends DecryptFragment { // handle messages by standard KeychainIntentServiceHandler first super.handleMessage(message); + // handle pending messages + if (handlePendingMessage(message)) { + return; + } + if (message.arg1 == MessageStatus.OKAY.ordinal()) { // get returned data bundle Bundle returnData = message.getData(); @@ -184,20 +195,20 @@ public class DecryptTextFragment extends DecryptFragment { DecryptVerifyResult pgpResult = returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); - if (pgpResult.isPending()) { - if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == - DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { - startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == - DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { - startPassphraseDialog(Constants.key.symmetric); - } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == - DecryptVerifyResult.RESULT_PENDING_NFC) { - startNfcDecrypt(pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); - } else { - throw new RuntimeException("Unhandled pending result!"); - } - } else if (pgpResult.success()) { +// if (pgpResult.isPending()) { +// if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == +// DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { +// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); +// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == +// DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { +// startPassphraseDialog(Constants.key.symmetric); +// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == +// DecryptVerifyResult.RESULT_PENDING_NFC) { +// startNfcDecrypt(pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); +// } else { +// throw new RuntimeException("Unhandled pending result!"); +// } + if (pgpResult.success()) { byte[] decryptedMessage = returnData .getByteArray(KeychainIntentService.RESULT_DECRYPTED_BYTES); @@ -245,34 +256,34 @@ public class DecryptTextFragment extends DecryptFragment { getActivity().startService(intent); } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - - case REQUEST_CODE_PASSPHRASE: { - if (resultCode == Activity.RESULT_OK && data != null) { - mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); - decryptStart(); - } else { - getActivity().finish(); - } - return; - } - - case REQUEST_CODE_NFC_DECRYPT: { - if (resultCode == Activity.RESULT_OK && data != null) { - mNfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); - decryptStart(); - } else { - getActivity().finish(); - } - return; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - } - } - } +// @Override +// public void onActivityResult(int requestCode, int resultCode, Intent data) { +// switch (requestCode) { +// +// case REQUEST_CODE_PASSPHRASE: { +// if (resultCode == Activity.RESULT_OK && data != null) { +// mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); +// decryptStart(); +// } else { +// getActivity().finish(); +// } +// return; +// } +// +// case REQUEST_CODE_NFC_DECRYPT: { +// if (resultCode == Activity.RESULT_OK && data != null) { +// mNfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); +// decryptStart(); +// } else { +// getActivity().finish(); +// } +// return; +// } +// +// default: { +// super.onActivityResult(requestCode, resultCode, data); +// } +// } +// } } -- cgit v1.2.3 From 95f1527afe81c59a116cadc2ed37c065da1819ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 29 Mar 2015 20:37:54 +0200 Subject: Fixing crashes with new encrypt ui --- .../keychain/ui/CryptoOperationFragment.java | 29 +++++++++++++++++----- .../keychain/ui/EncryptFilesFragment.java | 29 +++++++++++----------- .../keychain/ui/EncryptTextFragment.java | 23 +++++++++-------- 3 files changed, 49 insertions(+), 32 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java index 076c628b4..5227c1477 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java @@ -1,5 +1,22 @@ -package org.sufficientlysecure.keychain.ui; +/* + * Copyright (C) 2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser + * + * 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.app.Activity; import android.content.Intent; @@ -7,14 +24,15 @@ import android.os.Bundle; import android.os.Message; import android.support.v4.app.Fragment; -import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.operations.results.InputPendingResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; - +/** + * All fragments executing crypto operations need to extend this class. + */ public abstract class CryptoOperationFragment extends Fragment { public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; @@ -40,7 +58,6 @@ public abstract class CryptoOperationFragment extends Fragment { } throw new RuntimeException("Unhandled pending result!"); - } @Override @@ -77,8 +94,8 @@ public abstract class CryptoOperationFragment extends Fragment { if (message.arg1 == ServiceProgressHandler.MessageStatus.OKAY.ordinal()) { Bundle data = message.getData(); - OperationResult result = data.getParcelable(CertifyResult.EXTRA_RESULT); - if (result == null || ! (result instanceof InputPendingResult)) { + OperationResult result = data.getParcelable(OperationResult.EXTRA_RESULT); + if (result == null || !(result instanceof InputPendingResult)) { return false; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index fb9a86b07..5af353524 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -80,7 +80,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { private IMode mModeInterface; - private boolean mSymmetricMode = true; + private boolean mSymmetricMode = false; private boolean mUseArmor = false; private boolean mUseCompression = true; private boolean mDeleteAfterEncrypt = false; @@ -188,7 +188,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { if (mInputUris.contains(inputUri)) { Notify.create(getActivity(), getActivity().getString(R.string.error_file_added_already, FileHelper.getFilename(getActivity(), inputUri)), - Notify.Style.ERROR).show(this); + Notify.Style.ERROR).show(); return; } @@ -222,7 +222,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { private void encryptClicked(boolean share) { if (mInputUris.isEmpty()) { - Notify.create(getActivity(), R.string.error_no_file_selected, Notify.Style.ERROR).show(this); + Notify.create(getActivity(), R.string.error_no_file_selected, Notify.Style.ERROR).show(); return; } if (share) { @@ -238,7 +238,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { startEncrypt(true); } else { if (mInputUris.size() > 1) { - Notify.create(getActivity(), R.string.error_multi_not_supported, Notify.Style.ERROR).show(this); + Notify.create(getActivity(), R.string.error_multi_not_supported, Notify.Style.ERROR).show(); return; } showOutputFileDialog(); @@ -260,7 +260,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.encrypt_file_activity, menu); + inflater.inflate(R.menu.encrypt_file_fragment, menu); } @Override @@ -319,12 +319,14 @@ public class EncryptFilesFragment extends CryptoOperationFragment { if (mInputUris.isEmpty()) { Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR) - .show(this); + .show(); return false; } else if (mInputUris.size() > 1 && !mShareAfterEncrypt) { + Log.e(Constants.TAG, "Aborting: mInputUris.size() > 1 && !mShareAfterEncrypt"); // This should be impossible... return false; } else if (mInputUris.size() != mOutputUris.size()) { + Log.e(Constants.TAG, "Aborting: mInputUris.size() != mOutputUris.size()"); // This as well return false; } @@ -334,12 +336,12 @@ public class EncryptFilesFragment extends CryptoOperationFragment { if (mPassphrase == null) { Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR) - .show(this); + .show(); return false; } if (mPassphrase.isEmpty()) { Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) - .show(this); + .show(); return false; } @@ -352,7 +354,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { // Files must be encrypted, only text can be signed-only right now if (!gotEncryptionKeys) { Notify.create(getActivity(), R.string.select_encryption_key, Notify.Style.ERROR) - .show(this); + .show(); return false; } } @@ -361,7 +363,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { public void startEncrypt(boolean share) { mShareAfterEncrypt = share; - startEncrypt(); + cryptoOperation(new CryptoInputParcel()); } public void onEncryptSuccess(final SignEncryptResult result) { @@ -470,18 +472,15 @@ public class EncryptFilesFragment extends CryptoOperationFragment { return sendIntent; } - public void startEncrypt() { - cryptoOperation(new CryptoInputParcel()); - } - - // public void startEncrypt(CryptoInputParcel cryptoInput) { @Override protected void cryptoOperation(CryptoInputParcel cryptoInput) { if (!inputIsValid()) { // Notify was created by inputIsValid. + Log.d(Constants.TAG, "Input not valid!"); return; } + Log.d(Constants.TAG, "Input valid!"); // Send all information needed to service to edit key in other thread Intent intent = new Intent(getActivity(), KeychainIntentService.class); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index c71edcd22..3303b2c65 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -64,7 +64,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { private IMode mModeInterface; - private boolean mSymmetricMode = true; + private boolean mSymmetricMode = false; private boolean mShareAfterEncrypt = false; private boolean mUseCompression = true; private boolean mHiddenRecipients = false; @@ -159,7 +159,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.encrypt_text_activity, menu); + inflater.inflate(R.menu.encrypt_text_fragment, menu); } @Override @@ -289,7 +289,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { protected boolean inputIsValid() { if (mMessage == null) { Notify.create(getActivity(), R.string.error_message, Notify.Style.ERROR) - .show(this); + .show(); return false; } @@ -298,12 +298,12 @@ public class EncryptTextFragment extends CryptoOperationFragment { if (mPassphrase == null) { Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR) - .show(this); + .show(); return false; } if (mPassphrase.isEmpty()) { Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) - .show(this); + .show(); return false; } @@ -315,7 +315,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { if (!gotEncryptionKeys && mSigningKeyId == 0) { Notify.create(getActivity(), R.string.select_encryption_or_signature_key, Notify.Style.ERROR) - .show(this); + .show(); return false; } } @@ -348,7 +348,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { input.setCryptoInput(cryptoInput); } - Bundle data = new Bundle(); + final Bundle data = new Bundle(); data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -362,10 +362,11 @@ public class EncryptTextFragment extends CryptoOperationFragment { // handle messages by standard KeychainIntentServiceHandler first super.handleMessage(message); - // handle pending messages - if (handlePendingMessage(message)) { - return; - } + // TODO: We need a InputPendingResult! +// // handle pending messages +// if (handlePendingMessage(message)) { +// return; +// } if (message.arg1 == MessageStatus.OKAY.ordinal()) { SignEncryptResult result = -- cgit v1.2.3 From d7b79e55fba170a0fe691f00dbc943d8ecfff33e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 30 Mar 2015 16:40:41 +0200 Subject: pass CryptoInputParcel independently for SignEncryptOperation --- .../org/sufficientlysecure/keychain/ui/EncryptActivity.java | 8 +++----- .../sufficientlysecure/keychain/ui/EncryptFilesFragment.java | 10 ++++------ .../sufficientlysecure/keychain/ui/EncryptTextFragment.java | 5 +---- 3 files changed, 8 insertions(+), 15 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index a1edf808c..bd52d74cf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -106,7 +106,7 @@ public abstract class EncryptActivity extends BaseActivity { startEncrypt(null); } - public void startEncrypt(CryptoInputParcel cryptoInput) { + public void startEncrypt(final CryptoInputParcel cryptoInput) { if (!inputIsValid()) { // Notify was created by inputIsValid. return; @@ -117,12 +117,10 @@ public abstract class EncryptActivity extends BaseActivity { intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); final SignEncryptParcel input = createEncryptBundle(); - if (cryptoInput != null) { - input.setCryptoInput(cryptoInput); - } Bundle data = new Bundle(); data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); + data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Message is received after encrypting is done in KeychainIntentService @@ -151,7 +149,7 @@ public abstract class EncryptActivity extends BaseActivity { RequiredInputParcel parcel = RequiredInputParcel.createNfcSignOperation( pgpResult.getNfcHash(), pgpResult.getNfcAlgo(), - input.getSignatureTime()); + cryptoInput.getSignatureTime()); startNfcSign(pgpResult.getNfcKeyId(), parcel); } else { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 5af353524..7e4c48e10 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -93,8 +93,8 @@ public class EncryptFilesFragment extends CryptoOperationFragment { private long mSigningKeyId = Constants.key.none; private Passphrase mPassphrase = new Passphrase(); - private ArrayList mInputUris = new ArrayList(); - private ArrayList mOutputUris = new ArrayList(); + private ArrayList mInputUris = new ArrayList<>(); + private ArrayList mOutputUris = new ArrayList<>(); private ListView mSelectedFiles; private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter(); @@ -136,7 +136,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { try { mModeInterface = (IMode) activity; } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must be IMode"); + throw new ClassCastException(activity + " must be IMode"); } } @@ -487,12 +487,10 @@ public class EncryptFilesFragment extends CryptoOperationFragment { intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); final SignEncryptParcel input = createEncryptBundle(); - if (cryptoInput != null) { - input.setCryptoInput(cryptoInput); - } Bundle data = new Bundle(); data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); + data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Message is received after encrypting is done in KeychainIntentService diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index 3303b2c65..7197cf88d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -344,12 +344,9 @@ public class EncryptTextFragment extends CryptoOperationFragment { intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); final SignEncryptParcel input = createEncryptBundle(); - if (cryptoInput != null) { - input.setCryptoInput(cryptoInput); - } - final Bundle data = new Bundle(); data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); + data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Message is received after encrypting is done in KeychainIntentService -- cgit v1.2.3 From a3276a448528cee3ed392bf01e36835bbe8246ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 30 Mar 2015 20:41:29 +0200 Subject: Use RecyclerView in EncryptFilesFragment --- .../keychain/ui/CreateKeyEmailFragment.java | 25 +- .../keychain/ui/EncryptFilesFragment.java | 311 ++++++++++++++------- .../keychain/ui/EncryptModeAsymmetricFragment.java | 2 +- .../keychain/ui/adapter/SpacesItemDecoration.java | 93 ++++++ .../ui/dialog/DeleteFileDialogFragment.java | 21 +- 5 files changed, 331 insertions(+), 121 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SpacesItemDecoration.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java index 7e2e1c31c..85e2f8e9d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyEmailFragment.java @@ -126,7 +126,7 @@ public class CreateKeyEmailFragment extends Fragment { if (mAdditionalEmailModels == null) { mAdditionalEmailModels = new ArrayList<>(); if (mCreateKeyActivity.mAdditionalEmails != null) { - setAdditionalEmails(mCreateKeyActivity.mAdditionalEmails); + mEmailAdapter.addAll(mCreateKeyActivity.mAdditionalEmails); } } @@ -209,12 +209,6 @@ public class CreateKeyEmailFragment extends Fragment { return emails; } - private void setAdditionalEmails(ArrayList emails) { - for (String email : emails) { - mAdditionalEmailModels.add(new EmailAdapter.ViewModel(email)); - } - } - @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -244,8 +238,7 @@ public class CreateKeyEmailFragment extends Fragment { // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder - public static class ViewHolder extends RecyclerView.ViewHolder { - // each data item is just a string in this case + class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public ImageButton mDeleteButton; @@ -289,7 +282,10 @@ public class CreateKeyEmailFragment extends Fragment { // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { - if (holder instanceof ViewHolder) { + if (holder instanceof FooterHolder) { + FooterHolder thisHolder = (FooterHolder) holder; + thisHolder.mAddButton.setOnClickListener(mFooterOnClickListener); + } else if (holder instanceof ViewHolder) { ViewHolder thisHolder = (ViewHolder) holder; // - get element from your dataset at this position // - replace the contents of the view with that element @@ -302,9 +298,6 @@ public class CreateKeyEmailFragment extends Fragment { remove(model); } }); - } else if (holder instanceof FooterHolder) { - FooterHolder thisHolder = (FooterHolder) holder; - thisHolder.mAddButton.setOnClickListener(mFooterOnClickListener); } } @@ -332,6 +325,12 @@ public class CreateKeyEmailFragment extends Fragment { notifyItemInserted(mDataset.size() - 1); } + private void addAll(ArrayList emails) { + for (String email : emails) { + mDataset.add(new EmailAdapter.ViewModel(email)); + } + } + public void remove(ViewModel model) { int position = mDataset.indexOf(model); mDataset.remove(position); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 5af353524..dad8704fb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Dominik Schürmann + * Copyright (C) 2014-2015 Dominik Schürmann * * 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 @@ -17,7 +17,6 @@ package org.sufficientlysecure.keychain.ui; -import android.annotation.TargetApi; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; @@ -28,15 +27,17 @@ import android.os.Build; import android.os.Bundle; import android.os.Message; import android.os.Messenger; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.BaseAdapter; +import android.widget.Button; import android.widget.ImageView; -import android.widget.ListView; import android.widget.TextView; import org.spongycastle.bcpg.CompressionAlgorithmTags; @@ -50,6 +51,7 @@ import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.ui.adapter.SpacesItemDecoration; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; @@ -61,9 +63,8 @@ import org.sufficientlysecure.keychain.util.ShareHelper; import java.io.File; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; +import java.util.List; import java.util.Set; public class EncryptFilesFragment extends CryptoOperationFragment { @@ -93,12 +94,12 @@ public class EncryptFilesFragment extends CryptoOperationFragment { private long mSigningKeyId = Constants.key.none; private Passphrase mPassphrase = new Passphrase(); - private ArrayList mInputUris = new ArrayList(); - private ArrayList mOutputUris = new ArrayList(); + private ArrayList mOutputUris = new ArrayList<>(); - private ListView mSelectedFiles; - private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter(); - private final Map thumbnailCache = new HashMap<>(); + private RecyclerView mSelectedFiles; + + ArrayList mFilesModels; + FilesAdapter mFilesAdapter; /** * Creates new instance of this fragment @@ -146,17 +147,28 @@ public class EncryptFilesFragment extends CryptoOperationFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.encrypt_files_fragment, container, false); + mSelectedFiles = (RecyclerView) view.findViewById(R.id.selected_files_list); + + mSelectedFiles.addItemDecoration(new SpacesItemDecoration( + FormattingUtils.dpToPx(getActivity(), 4))); + mSelectedFiles.setHasFixedSize(true); + mSelectedFiles.setLayoutManager(new LinearLayoutManager(getActivity())); + mSelectedFiles.setItemAnimator(new DefaultItemAnimator()); - View addView = inflater.inflate(R.layout.file_list_entry_add, null); - addView.setOnClickListener(new View.OnClickListener() { + mFilesModels = new ArrayList<>(); + mFilesAdapter = new FilesAdapter(getActivity(), mFilesModels, new View.OnClickListener() { @Override public void onClick(View v) { addInputUri(); } }); - mSelectedFiles = (ListView) view.findViewById(R.id.selected_files_list); - mSelectedFiles.addFooterView(addView); - mSelectedFiles.setAdapter(mAdapter); + + ArrayList inputUris = getArguments().getParcelableArrayList(ARG_URIS); + if (inputUris != null) { + mFilesAdapter.addAll(inputUris); + } + mUseArmor = getArguments().getBoolean(ARG_USE_ASCII_ARMOR); + mSelectedFiles.setAdapter(mFilesAdapter); return view; } @@ -165,17 +177,14 @@ public class EncryptFilesFragment extends CryptoOperationFragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); - - mInputUris = getArguments().getParcelableArrayList(ARG_URIS); - mUseArmor = getArguments().getBoolean(ARG_USE_ASCII_ARMOR); } private void addInputUri() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { FileHelper.openDocument(EncryptFilesFragment.this, "*/*", true, REQUEST_CODE_INPUT); } else { - FileHelper.openFile(EncryptFilesFragment.this, mInputUris.isEmpty() ? - null : mInputUris.get(mInputUris.size() - 1), + FileHelper.openFile(EncryptFilesFragment.this, mFilesModels.isEmpty() ? + null : mFilesModels.get(mFilesModels.size() - 1).inputUri, "*/*", REQUEST_CODE_INPUT); } } @@ -185,32 +194,27 @@ public class EncryptFilesFragment extends CryptoOperationFragment { return; } - if (mInputUris.contains(inputUri)) { + if (mFilesAdapter.getAsArrayList().contains(inputUri)) { Notify.create(getActivity(), getActivity().getString(R.string.error_file_added_already, FileHelper.getFilename(getActivity(), inputUri)), Notify.Style.ERROR).show(); return; } - mInputUris.add(inputUri); - mSelectedFiles.requestFocus(); - } - - private void delInputUri(int position) { - mInputUris.remove(position); + mFilesAdapter.add(inputUri); mSelectedFiles.requestFocus(); } private void showOutputFileDialog() { - if (mInputUris.size() > 1 || mInputUris.isEmpty()) { + if (mFilesModels.size() > 1 || mFilesModels.isEmpty()) { throw new IllegalStateException(); } - Uri inputUri = mInputUris.get(0); + FilesAdapter.ViewModel model = mFilesModels.get(0); String targetName = - (mEncryptFilenames ? "1" : FileHelper.getFilename(getActivity(), inputUri)) + (mEncryptFilenames ? "1" : FileHelper.getFilename(getActivity(), model.inputUri)) + (mUseArmor ? Constants.FILE_EXTENSION_ASC : Constants.FILE_EXTENSION_PGP_MAIN); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - File file = new File(inputUri.getPath()); + File file = new File(model.inputUri.getPath()); File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR; File targetFile = new File(parentDir, targetName); FileHelper.saveFile(this, getString(R.string.title_encrypt_to_file), @@ -221,40 +225,48 @@ public class EncryptFilesFragment extends CryptoOperationFragment { } private void encryptClicked(boolean share) { - if (mInputUris.isEmpty()) { - Notify.create(getActivity(), R.string.error_no_file_selected, Notify.Style.ERROR).show(); + if (mFilesModels.isEmpty()) { + Notify.create(getActivity(), R.string.error_no_file_selected, + Notify.Style.ERROR).show(); return; } if (share) { mOutputUris.clear(); int filenameCounter = 1; - for (Uri uri : mInputUris) { + for (FilesAdapter.ViewModel model : mFilesModels) { String targetName = - (mEncryptFilenames ? String.valueOf(filenameCounter) : FileHelper.getFilename(getActivity(), uri)) + (mEncryptFilenames ? String.valueOf(filenameCounter) : FileHelper.getFilename(getActivity(), model.inputUri)) + (mUseArmor ? Constants.FILE_EXTENSION_ASC : Constants.FILE_EXTENSION_PGP_MAIN); mOutputUris.add(TemporaryStorageProvider.createFile(getActivity(), targetName)); filenameCounter++; } startEncrypt(true); } else { - if (mInputUris.size() > 1) { - Notify.create(getActivity(), R.string.error_multi_not_supported, Notify.Style.ERROR).show(); + if (mFilesModels.size() > 1) { + Notify.create(getActivity(), R.string.error_multi_not_supported, + Notify.Style.ERROR).show(); return; } showOutputFileDialog(); } } - @TargetApi(Build.VERSION_CODES.KITKAT) - public boolean handleClipData(Intent data) { - if (data.getClipData() != null && data.getClipData().getItemCount() > 0) { - for (int i = 0; i < data.getClipData().getItemCount(); i++) { - Uri uri = data.getClipData().getItemAt(i).getUri(); - if (uri != null) addInputUri(uri); + public void addFile(Intent data) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + addInputUri(data.getData()); + } else { + if (data.getClipData() != null && data.getClipData().getItemCount() > 0) { + for (int i = 0; i < data.getClipData().getItemCount(); i++) { + Uri uri = data.getClipData().getItemAt(i).getUri(); + if (uri != null) { + addInputUri(uri); + } + } + } else { + // fallback, try old method to get single uri + addInputUri(data.getData()); } - return true; } - return false; } @Override @@ -284,22 +296,18 @@ public class EncryptFilesFragment extends CryptoOperationFragment { } case R.id.check_use_armor: { mUseArmor = item.isChecked(); -// notifyUpdate(); break; } case R.id.check_delete_after_encrypt: { mDeleteAfterEncrypt = item.isChecked(); -// notifyUpdate(); break; } case R.id.check_enable_compression: { mUseCompression = item.isChecked(); -// onNotifyUpdate(); break; } case R.id.check_encrypt_filenames: { mEncryptFilenames = item.isChecked(); -// onNotifyUpdate(); break; } // case R.id.check_hidden_recipients: { @@ -317,15 +325,15 @@ public class EncryptFilesFragment extends CryptoOperationFragment { protected boolean inputIsValid() { // file checks - if (mInputUris.isEmpty()) { + if (mFilesModels.isEmpty()) { Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR) .show(); return false; - } else if (mInputUris.size() > 1 && !mShareAfterEncrypt) { + } else if (mFilesModels.size() > 1 && !mShareAfterEncrypt) { Log.e(Constants.TAG, "Aborting: mInputUris.size() > 1 && !mShareAfterEncrypt"); // This should be impossible... return false; - } else if (mInputUris.size() != mOutputUris.size()) { + } else if (mFilesModels.size() != mOutputUris.size()) { Log.e(Constants.TAG, "Aborting: mInputUris.size() != mOutputUris.size()"); // This as well return false; @@ -368,8 +376,8 @@ public class EncryptFilesFragment extends CryptoOperationFragment { public void onEncryptSuccess(final SignEncryptResult result) { if (mDeleteAfterEncrypt) { - final Uri[] inputUris = mInputUris.toArray(new Uri[mInputUris.size()]); - DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(inputUris); + DeleteFileDialogFragment deleteFileDialog = + DeleteFileDialogFragment.newInstance(mFilesAdapter.getAsArrayList()); deleteFileDialog.setOnDeletedListener(new DeleteFileDialogFragment.OnDeletedListener() { @Override @@ -386,8 +394,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { }); deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog"); - mInputUris.clear(); - onNotifyUpdate(); + mFilesModels.clear(); } else { if (mShareAfterEncrypt) { // Share encrypted message/file @@ -403,7 +410,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { // fill values for this action SignEncryptParcel data = new SignEncryptParcel(); - data.addInputUris(mInputUris); + data.addInputUris(mFilesAdapter.getAsArrayList()); data.addOutputUris(mOutputUris); if (mUseCompression) { @@ -563,9 +570,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { switch (requestCode) { case REQUEST_CODE_INPUT: { if (resultCode == Activity.RESULT_OK && data != null) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT || !handleClipData(data)) { - addInputUri(data.getData()); - } + addFile(data); } return; } @@ -574,7 +579,6 @@ public class EncryptFilesFragment extends CryptoOperationFragment { if (resultCode == Activity.RESULT_OK && data != null) { mOutputUris.clear(); mOutputUris.add(data.getData()); - onNotifyUpdate(); startEncrypt(false); } return; @@ -588,66 +592,167 @@ public class EncryptFilesFragment extends CryptoOperationFragment { } } - public void onNotifyUpdate() { - // Clear cache if needed - for (Uri uri : new HashSet<>(thumbnailCache.keySet())) { - if (!mInputUris.contains(uri)) { - thumbnailCache.remove(uri); + public static class FilesAdapter extends RecyclerView.Adapter { + private Activity mActivity; + private List mDataset; + private View.OnClickListener mFooterOnClickListener; + private static final int TYPE_FOOTER = 0; + private static final int TYPE_ITEM = 1; + + public static class ViewModel { + Uri inputUri; + Bitmap thumbnail; + String filename; + long fileSize; + + ViewModel(Uri inputUri, Bitmap thumbnail, String filename, long fileSize) { + this.inputUri = inputUri; + this.thumbnail = thumbnail; + this.filename = filename; + this.fileSize = fileSize; + } + + @Override + public String toString() { + return inputUri.toString(); } } - mAdapter.notifyDataSetChanged(); - } + // Provide a reference to the views for each data item + // Complex data items may need more than one view per item, and + // you provide access to all the views for a data item in a view holder + class ViewHolder extends RecyclerView.ViewHolder { + public TextView filename; + public TextView fileSize; + public View removeButton; + public ImageView thumbnail; + + public ViewHolder(View itemView) { + super(itemView); + filename = (TextView) itemView.findViewById(R.id.filename); + fileSize = (TextView) itemView.findViewById(R.id.filesize); + removeButton = itemView.findViewById(R.id.action_remove_file_from_list); + thumbnail = (ImageView) itemView.findViewById(R.id.thumbnail); + } + } - private class SelectedFilesAdapter extends BaseAdapter { + class FooterHolder extends RecyclerView.ViewHolder { + public Button mAddButton; + + public FooterHolder(View itemView) { + super(itemView); + mAddButton = (Button) itemView.findViewById(R.id.file_list_entry_add); + } + } + + // Provide a suitable constructor (depends on the kind of dataset) + public FilesAdapter(Activity activity, List myDataset, View.OnClickListener onFooterClickListener) { + mActivity = activity; + mDataset = myDataset; + mFooterOnClickListener = onFooterClickListener; + } + + // Create new views (invoked by the layout manager) @Override - public int getCount() { - return mInputUris.size(); + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if (viewType == TYPE_FOOTER) { + View v = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.file_list_entry_add, parent, false); + return new FooterHolder(v); + } else { + //inflate your layout and pass it to view holder + View v = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.file_list_entry, parent, false); + return new ViewHolder(v); + } } + // Replace the contents of a view (invoked by the layout manager) @Override - public Object getItem(int position) { - return mInputUris.get(position); + public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { + if (holder instanceof FooterHolder) { + FooterHolder thisHolder = (FooterHolder) holder; + thisHolder.mAddButton.setOnClickListener(mFooterOnClickListener); + } else if (holder instanceof ViewHolder) { + ViewHolder thisHolder = (ViewHolder) holder; + // - get element from your dataset at this position + // - replace the contents of the view with that element + final ViewModel model = mDataset.get(position); + + thisHolder.filename.setText(model.filename); + if (model.fileSize == -1) { + thisHolder.fileSize.setText(""); + } else { + thisHolder.fileSize.setText(FileHelper.readableFileSize(model.fileSize)); + } + thisHolder.removeButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + remove(model); + } + }); + if (model.thumbnail != null) { + thisHolder.thumbnail.setImageBitmap(model.thumbnail); + } else { + thisHolder.thumbnail.setImageResource(R.drawable.ic_doc_generic_am); + } + } } + // Return the size of your dataset (invoked by the layout manager) @Override - public long getItemId(int position) { - return getItem(position).hashCode(); + public int getItemCount() { + return mDataset.size() + 1; } @Override - public View getView(final int position, View convertView, ViewGroup parent) { - Uri inputUri = mInputUris.get(position); - View view; - if (convertView == null) { - view = getActivity().getLayoutInflater().inflate(R.layout.file_list_entry, null); - } else { - view = convertView; - } - ((TextView) view.findViewById(R.id.filename)).setText(FileHelper.getFilename(getActivity(), inputUri)); - long size = FileHelper.getFileSize(getActivity(), inputUri); - if (size == -1) { - ((TextView) view.findViewById(R.id.filesize)).setText(""); + public int getItemViewType(int position) { + if (isPositionFooter(position)) { + return TYPE_FOOTER; } else { - ((TextView) view.findViewById(R.id.filesize)).setText(FileHelper.readableFileSize(size)); + return TYPE_ITEM; } - view.findViewById(R.id.action_remove_file_from_list).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - delInputUri(position); + } + + private boolean isPositionFooter(int position) { + return position == mDataset.size(); + } + + public void add(Uri inputUri) { + mDataset.add(createModel(inputUri)); + notifyItemInserted(mDataset.size() - 1); + } + + public void addAll(ArrayList inputUris) { + if (inputUris != null) { + for (Uri inputUri : inputUris) { + mDataset.add(createModel(inputUri)); } - }); - int px = FormattingUtils.dpToPx(getActivity(), 48); - if (!thumbnailCache.containsKey(inputUri)) { - thumbnailCache.put(inputUri, FileHelper.getThumbnail(getActivity(), inputUri, new Point(px, px))); } - Bitmap bitmap = thumbnailCache.get(inputUri); - if (bitmap != null) { - ((ImageView) view.findViewById(R.id.thumbnail)).setImageBitmap(bitmap); - } else { - ((ImageView) view.findViewById(R.id.thumbnail)).setImageResource(R.drawable.ic_doc_generic_am); + // TODO: notifyItemInserted? + } + + private ViewModel createModel(Uri inputUri) { + int px = FormattingUtils.dpToPx(mActivity, 48); + Bitmap thumbnail = FileHelper.getThumbnail(mActivity, inputUri, new Point(px, px)); + String filename = FileHelper.getFilename(mActivity, inputUri); + long size = FileHelper.getFileSize(mActivity, inputUri); + return new ViewModel(inputUri, thumbnail, filename, size); + } + + public void remove(ViewModel model) { + int position = mDataset.indexOf(model); + mDataset.remove(position); + notifyItemRemoved(position); + } + + public ArrayList getAsArrayList() { + ArrayList uris = new ArrayList<>(); + for (ViewModel model : mDataset) { + uris.add(model.inputUri); } - return view; + return uris; } + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java index 87c6c477c..6f56f2dc4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java @@ -65,7 +65,7 @@ public class EncryptModeAsymmetricFragment extends Fragment { private IAsymmetric mEncryptInterface; // @Override -// public void onNotifyUpdate() { +// public void updateUi() { // if (mSign != null) { // mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey()); // } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SpacesItemDecoration.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SpacesItemDecoration.java new file mode 100644 index 000000000..bc595803b --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SpacesItemDecoration.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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.adapter; + +import android.graphics.Rect; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +/** + * https://gist.github.com/yrom/3b4bcbc2370ca2290434 + */ +public class SpacesItemDecoration extends RecyclerView.ItemDecoration { + private int space; + private int spanCount; + private int lastItemInFirstLane = -1; + + public SpacesItemDecoration(int space) { + this(space, 1); + } + + /** + * @param space + * @param spanCount spans count of one lane + */ + public SpacesItemDecoration(int space, int spanCount) { + this.space = space; + this.spanCount = spanCount; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams(); + final int position = params.getViewPosition(); + final int spanSize; + final int index; + if (params instanceof GridLayoutManager.LayoutParams) { + GridLayoutManager.LayoutParams gridParams = (GridLayoutManager.LayoutParams) params; + spanSize = gridParams.getSpanSize(); + index = gridParams.getSpanIndex(); + } else { + spanSize = 1; + index = position % spanCount; + } + // invalid value + if (spanSize < 1 || index < 0) return; + + if (spanSize == spanCount) { // full span + outRect.left = space; + outRect.right = space; + } else { + if (index == 0) { // left one + outRect.left = space; + } + // spanCount >= 1 + if (index == spanCount - 1) { // right one + outRect.right = space; + } + if (outRect.left == 0) { + outRect.left = space / 2; + } + if (outRect.right == 0) { + outRect.right = space / 2; + } + } + // set top to all in first lane + if (position < spanCount && spanSize <= spanCount) { + if (lastItemInFirstLane < 0) { // lay out at first time + lastItemInFirstLane = position + spanSize == spanCount ? position : lastItemInFirstLane; + outRect.top = space; + } else if (position <= lastItemInFirstLane) { // scroll to first lane again + outRect.top = space; + } + } + outRect.bottom = space; + + } +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java index bd4e5577b..956171349 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java @@ -44,11 +44,24 @@ public class DeleteFileDialogFragment extends DialogFragment { /** * Creates new instance of this delete file dialog fragment */ - public static DeleteFileDialogFragment newInstance(Uri... deleteUris) { + public static DeleteFileDialogFragment newInstance(ArrayList deleteUris) { DeleteFileDialogFragment frag = new DeleteFileDialogFragment(); Bundle args = new Bundle(); - args.putParcelableArray(ARG_DELETE_URIS, deleteUris); + args.putParcelableArrayList(ARG_DELETE_URIS, deleteUris); + + frag.setArguments(args); + + return frag; + } + + public static DeleteFileDialogFragment newInstance(Uri deleteUri) { + DeleteFileDialogFragment frag = new DeleteFileDialogFragment(); + Bundle args = new Bundle(); + + ArrayList list = new ArrayList<>(); + list.add(deleteUri); + args.putParcelableArrayList(ARG_DELETE_URIS, list); frag.setArguments(args); @@ -62,7 +75,7 @@ public class DeleteFileDialogFragment extends DialogFragment { public Dialog onCreateDialog(Bundle savedInstanceState) { final FragmentActivity activity = getActivity(); - final Uri[] deleteUris = (Uri[]) getArguments().getParcelableArray(ARG_DELETE_URIS); + final ArrayList deleteUris = getArguments().getParcelableArrayList(ARG_DELETE_URIS); final StringBuilder deleteFileNames = new StringBuilder(); //Retrieving file names after deletion gives unexpected results @@ -127,7 +140,7 @@ public class DeleteFileDialogFragment extends DialogFragment { // NOTE: Use Toasts, not Snackbars. When sharing to another application snackbars // would not show up! Toast.makeText(getActivity(), getActivity().getString(R.string.file_delete_successful, - deleteUris.length - failedFileNameList.size(), deleteUris.length, failedFileNames.toString()), + deleteUris.size() - failedFileNameList.size(), deleteUris.size(), failedFileNames.toString()), Toast.LENGTH_LONG).show(); if (onDeletedListener != null) { -- cgit v1.2.3 From d67b546ec52c94faf71733b063856de98d66ef01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 30 Mar 2015 23:23:54 +0200 Subject: Dont show slinger button in spinner --- .../java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java index 9304b14f1..6f19fc6ed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java @@ -147,6 +147,8 @@ public class KeyAdapter extends CursorAdapter { mStatus.setVisibility(View.GONE); if (mSlingerButton.hasOnClickListeners()) { mSlinger.setVisibility(View.VISIBLE); + } else { + mSlinger.setVisibility(View.GONE); } mMainUserId.setTextColor(context.getResources().getColor(R.color.black)); mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black)); -- cgit v1.2.3 From 39b131c7e58c358adf93bb64fe297884664a4ae1 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 30 Mar 2015 23:35:32 +0200 Subject: fix Encrypt* with RequiredInputParcel --- .../keychain/ui/CryptoOperationFragment.java | 6 +- .../keychain/ui/DecryptFilesFragment.java | 2 +- .../keychain/ui/DecryptFragment.java | 2 +- .../keychain/ui/EncryptActivity.java | 189 --------------------- .../keychain/ui/EncryptFilesFragment.java | 27 +-- .../keychain/ui/EncryptTextActivity.java | 2 +- .../keychain/ui/EncryptTextFragment.java | 52 ++---- .../keychain/ui/NfcActivity.java | 4 +- .../keychain/ui/NfcOperationActivity.java | 22 ++- .../keychain/ui/PassphraseDialogActivity.java | 21 +-- .../keychain/ui/base/BaseNfcActivity.java | 2 +- 11 files changed, 48 insertions(+), 281 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java index 5227c1477..b632509bb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java @@ -66,7 +66,7 @@ public abstract class CryptoOperationFragment extends Fragment { case REQUEST_CODE_PASSPHRASE: { if (resultCode == Activity.RESULT_OK && data != null) { CryptoInputParcel cryptoInput = - data.getParcelableExtra(PassphraseDialogActivity.RESULT_DATA); + data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT); cryptoOperation(cryptoInput); return; } @@ -110,6 +110,10 @@ public abstract class CryptoOperationFragment extends Fragment { return false; } + protected void cryptoOperation() { + cryptoOperation(new CryptoInputParcel()); + } + protected abstract void cryptoOperation(CryptoInputParcel cryptoInput); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java index ecc99b348..d1c005868 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java @@ -198,7 +198,7 @@ public class DecryptFilesFragment extends DecryptFragment { // data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); // data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); // -// intent.putExtra(KeychainIntentService.EXTRA_DATA, data); +// intent.putExtra(KeychainIntentService.EXTRA_SERVICE_INTENT, data); // // // Message is received after decrypting is done in KeychainIntentService // ServiceProgressHandler saveHandler = new ServiceProgressHandler( diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index f00136d5b..38ad54ad3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -105,7 +105,7 @@ public abstract class DecryptFragment extends CryptoOperationFragment { // // build PendingIntent for Yubikey NFC operations // Intent intent = new Intent(getActivity(), NfcActivity.class); // intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY); -// intent.putExtra(NfcActivity.EXTRA_DATA, new Intent()); // not used, only relevant to OpenPgpService +// intent.putExtra(NfcActivity.EXTRA_SERVICE_INTENT, new Intent()); // not used, only relevant to OpenPgpService // intent.putExtra(NfcActivity.EXTRA_KEY_ID, subKeyId); // intent.putExtra(NfcActivity.EXTRA_PIN, pin); // diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java deleted file mode 100644 index bd52d74cf..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * 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.app.Activity; -import android.app.ProgressDialog; -import android.content.Intent; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.view.View; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; -import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; -import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; -import org.sufficientlysecure.keychain.ui.base.BaseActivity; -import org.sufficientlysecure.keychain.service.ServiceProgressHandler; -import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; -import org.sufficientlysecure.keychain.util.Passphrase; - -public abstract class EncryptActivity extends BaseActivity { - - public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; - public static final int REQUEST_CODE_NFC = 0x00008002; - - // For NFC data - protected Passphrase mSigningKeyPassphrase = null; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setFullScreenDialogClose(new View.OnClickListener() { - @Override - public void onClick(View v) { - setResult(Activity.RESULT_CANCELED); - finish(); - } - }, false); - } - - protected void startPassphraseDialog(long subkeyId) { - Intent intent = new Intent(this, PassphraseDialogActivity.class); - intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId); - startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); - } - - protected void startNfcSign(long keyId, RequiredInputParcel nfcOps) { - - Intent intent = new Intent(this, NfcOperationActivity.class); - intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, nfcOps); - // TODO respect keyid(?) - - startActivityForResult(intent, REQUEST_CODE_NFC); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CODE_PASSPHRASE: { - if (resultCode == RESULT_OK && data != null) { - mSigningKeyPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); - startEncrypt(); - return; - } - break; - } - - case REQUEST_CODE_NFC: { - if (resultCode == RESULT_OK && data != null) { - CryptoInputParcel cryptoInput = - data.getParcelableExtra(NfcOperationActivity.RESULT_DATA); - startEncrypt(cryptoInput); - return; - } - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - break; - } - } - } - - public void startEncrypt() { - startEncrypt(null); - } - - public void startEncrypt(final CryptoInputParcel cryptoInput) { - if (!inputIsValid()) { - // Notify was created by inputIsValid. - return; - } - - // Send all information needed to service to edit key in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); - - final SignEncryptParcel input = createEncryptBundle(); - - Bundle data = new Bundle(); - data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, input); - data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after encrypting is done in KeychainIntentService - ServiceProgressHandler serviceHandler = new ServiceProgressHandler( - this, - getString(R.string.progress_encrypting), - ProgressDialog.STYLE_HORIZONTAL, - ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == MessageStatus.OKAY.ordinal()) { - SignEncryptResult result = - message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); - - PgpSignEncryptResult pgpResult = result.getPending(); - - if (pgpResult != null && pgpResult.isPending()) { - if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == - PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { - startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == - PgpSignEncryptResult.RESULT_PENDING_NFC) { - - RequiredInputParcel parcel = RequiredInputParcel.createNfcSignOperation( - pgpResult.getNfcHash(), - pgpResult.getNfcAlgo(), - cryptoInput.getSignatureTime()); - startNfcSign(pgpResult.getNfcKeyId(), parcel); - - } else { - throw new RuntimeException("Unhandled pending result!"); - } - return; - } - - if (result.success()) { - onEncryptSuccess(result); - } else { - result.createNotify(EncryptActivity.this).show(); - } - - // no matter the result, reset parameters - mSigningKeyPassphrase = null; - } - } - }; - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(serviceHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - serviceHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } - - protected abstract boolean inputIsValid(); - - protected abstract void onEncryptSuccess(SignEncryptResult result); - - protected abstract SignEncryptParcel createEncryptBundle(); - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 7e4c48e10..b320c8a50 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -363,7 +363,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { public void startEncrypt(boolean share) { mShareAfterEncrypt = share; - cryptoOperation(new CryptoInputParcel()); + cryptoOperation(); } public void onEncryptSuccess(final SignEncryptResult result) { @@ -512,36 +512,11 @@ public class EncryptFilesFragment extends CryptoOperationFragment { if (message.arg1 == MessageStatus.OKAY.ordinal()) { SignEncryptResult result = message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); - -// PgpSignEncryptResult pgpResult = result.getPending(); -// -// if (pgpResult != null && pgpResult.isPending()) { -// if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == -// PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { -// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); -// } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == -// PgpSignEncryptResult.RESULT_PENDING_NFC) { -// -// RequiredInputParcel parcel = RequiredInputParcel.createNfcSignOperation( -// pgpResult.getNfcHash(), -// pgpResult.getNfcAlgo(), -// input.getSignatureTime()); -// startNfcSign(pgpResult.getNfcKeyId(), parcel); -// -// } else { -// throw new RuntimeException("Unhandled pending result!"); -// } -// return; -// } - if (result.success()) { onEncryptSuccess(result); } else { result.createNotify(getActivity()).show(); } - - // no matter the result, reset parameters -// mSigningKeyPassphrase = null; } } }; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 2ffb29b09..03ab48e23 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -160,6 +160,6 @@ public class EncryptTextActivity extends BaseActivity implements @Override public void onPassphraseChanged(Passphrase passphrase) { - mEncryptFragment.setPassphrase(passphrase); + mEncryptFragment.setSymmetricPassphrase(passphrase); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index 7197cf88d..fecc9ef52 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -37,7 +37,6 @@ import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.PgpConstants; @@ -73,7 +72,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { private String mEncryptionUserIds[] = null; // TODO Constants.key.none? What's wrong with a null value? private long mSigningKeyId = Constants.key.none; - private Passphrase mPassphrase = new Passphrase(); + private Passphrase mSymmetricPassphrase = new Passphrase(); private String mMessage = ""; private TextView mText; @@ -90,8 +89,8 @@ public class EncryptTextFragment extends CryptoOperationFragment { mSigningKeyId = signingKeyId; } - public void setPassphrase(Passphrase passphrase) { - mPassphrase = passphrase; + public void setSymmetricPassphrase(Passphrase passphrase) { + mSymmetricPassphrase = passphrase; } /** @@ -233,7 +232,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { if (mSymmetricMode) { Log.d(Constants.TAG, "Symmetric encryption enabled!"); - Passphrase passphrase = mPassphrase; + Passphrase passphrase = mSymmetricPassphrase; if (passphrase.isEmpty()) { passphrase = null; } @@ -241,7 +240,6 @@ public class EncryptTextFragment extends CryptoOperationFragment { } else { data.setEncryptionMasterKeyIds(mEncryptionKeyIds); data.setSignatureMasterKeyId(mSigningKeyId); -// data.setSignaturePassphrase(mSigningKeyPassphrase); } return data; } @@ -296,12 +294,12 @@ public class EncryptTextFragment extends CryptoOperationFragment { if (mSymmetricMode) { // symmetric encryption checks - if (mPassphrase == null) { + if (mSymmetricPassphrase == null) { Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR) .show(); return false; } - if (mPassphrase.isEmpty()) { + if (mSymmetricPassphrase.isEmpty()) { Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) .show(); return false; @@ -325,11 +323,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { public void startEncrypt(boolean share) { mShareAfterEncrypt = share; - startEncrypt(); - } - - public void startEncrypt() { - cryptoOperation(null); + cryptoOperation(); } @Override @@ -359,45 +353,19 @@ public class EncryptTextFragment extends CryptoOperationFragment { // handle messages by standard KeychainIntentServiceHandler first super.handleMessage(message); - // TODO: We need a InputPendingResult! -// // handle pending messages -// if (handlePendingMessage(message)) { -// return; -// } + if (handlePendingMessage(message)) { + return; + } if (message.arg1 == MessageStatus.OKAY.ordinal()) { SignEncryptResult result = message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); - PgpSignEncryptResult pgpResult = result.getPending(); - -// if (pgpResult != null && pgpResult.isPending()) { -// if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == -// PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { -// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); -// } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == -// PgpSignEncryptResult.RESULT_PENDING_NFC) { -// -// RequiredInputParcel parcel = RequiredInputParcel.createNfcSignOperation( -// pgpResult.getNfcHash(), -// pgpResult.getNfcAlgo(), -// input.getSignatureTime()); -// startNfcSign(pgpResult.getNfcKeyId(), parcel); -// -// } else { -// throw new RuntimeException("Unhandled pending result!"); -// } -// return; -// } - if (result.success()) { onEncryptSuccess(result); } else { result.createNotify(getActivity()).show(); } - - // no matter the result, reset parameters -// mSigningKeyPassphrase = null; } } }; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java index 57acf3e93..1cb5a41a7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java @@ -100,7 +100,7 @@ public class NfcActivity extends BaseActivity { Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); Log.d(Constants.TAG, "NfcActivity mHashToSign as hex: " + getHex(mHashToSign)); - Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); + Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent); break; case ACTION_DECRYPT_SESSION_KEY: mAction = action; @@ -111,7 +111,7 @@ public class NfcActivity extends BaseActivity { Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); Log.d(Constants.TAG, "NfcActivity mEncryptedSessionKey as hex: " + getHex(mEncryptedSessionKey)); - Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); + Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent); break; case NfcAdapter.ACTION_TAG_DISCOVERED: Log.e(Constants.TAG, "This should not happen! NfcActivity.onCreate() is being called instead of onNewIntent()!"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index 511183b04..d70b0aad1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -10,8 +10,10 @@ import android.annotation.TargetApi; import android.content.Intent; import android.os.Build; import android.os.Bundle; +import android.os.Parcelable; import android.view.WindowManager; +import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.service.PassphraseCacheService; @@ -34,9 +36,13 @@ public class NfcOperationActivity extends BaseNfcActivity { public static final String EXTRA_REQUIRED_INPUT = "required_input"; + // passthrough for OpenPgpService + public static final String EXTRA_SERVICE_INTENT = "data"; + public static final String RESULT_DATA = "result_data"; - RequiredInputParcel mRequiredInput; + private RequiredInputParcel mRequiredInput; + private Intent mServiceIntent; @Override protected void onCreate(Bundle savedInstanceState) { @@ -49,6 +55,7 @@ public class NfcOperationActivity extends BaseNfcActivity { Bundle data = intent.getExtras(); mRequiredInput = data.getParcelable(EXTRA_REQUIRED_INPUT); + mServiceIntent = data.getParcelable(EXTRA_SERVICE_INTENT); // obtain passphrase for this subkey obtainYubikeyPin(RequiredInputParcel.createRequiredPassphrase(mRequiredInput)); @@ -84,10 +91,15 @@ public class NfcOperationActivity extends BaseNfcActivity { break; } - // give data through for new service call - Intent result = new Intent(); - result.putExtra(NfcOperationActivity.RESULT_DATA, resultData); - setResult(RESULT_OK, result); + if (mServiceIntent != null) { + mServiceIntent.putExtra(OpenPgpApi.EXTRA_CRYPTO_INPUT, resultData); + setResult(RESULT_OK, mServiceIntent); + } else { + Intent result = new Intent(); + result.putExtra(NfcOperationActivity.RESULT_DATA, resultData); + setResult(RESULT_OK, result); + } + finish(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index 9e04426eb..c1771ce57 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -41,7 +41,7 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; -import junit.framework.Assert; +import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; @@ -67,14 +67,13 @@ import org.sufficientlysecure.keychain.util.Preferences; * This activity encapsulates a DialogFragment to emulate a dialog. */ public class PassphraseDialogActivity extends FragmentActivity { - public static final String MESSAGE_DATA_PASSPHRASE = "passphrase"; - public static final String RESULT_DATA = "result_data"; + public static final String RESULT_CRYPTO_INPUT = "result_data"; public static final String EXTRA_REQUIRED_INPUT = "required_input"; public static final String EXTRA_SUBKEY_ID = "secret_key_id"; // special extra for OpenPgpService - public static final String EXTRA_DATA = "data"; + public static final String EXTRA_SERVICE_INTENT = "data"; private static final int REQUEST_CODE_ENTER_PATTERN = 2; @@ -104,7 +103,7 @@ public class PassphraseDialogActivity extends FragmentActivity { keyId = requiredInput.getSubKeyId(); } - Intent serviceIntent = getIntent().getParcelableExtra(EXTRA_DATA); + Intent serviceIntent = getIntent().getParcelableExtra(EXTRA_SERVICE_INTENT); show(this, keyId, serviceIntent); } @@ -155,7 +154,7 @@ public class PassphraseDialogActivity extends FragmentActivity { PassphraseDialogFragment frag = new PassphraseDialogFragment(); Bundle args = new Bundle(); args.putLong(EXTRA_SUBKEY_ID, keyId); - args.putParcelable(EXTRA_DATA, serviceIntent); + args.putParcelable(EXTRA_SERVICE_INTENT, serviceIntent); frag.setArguments(args); @@ -188,7 +187,7 @@ public class PassphraseDialogActivity extends FragmentActivity { R.style.Theme_AppCompat_Light_Dialog); mSubKeyId = getArguments().getLong(EXTRA_SUBKEY_ID); - mServiceIntent = getArguments().getParcelable(EXTRA_DATA); + mServiceIntent = getArguments().getParcelable(EXTRA_SERVICE_INTENT); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); @@ -418,15 +417,13 @@ public class PassphraseDialogActivity extends FragmentActivity { } if (mServiceIntent != null) { - // TODO: Not routing passphrase through OpenPGP API currently - // due to security concerns... - // BUT this means you need to _cache_ passphrases! + // TODO really pass this through the PendingIntent? + mServiceIntent.putExtra(OpenPgpApi.EXTRA_CRYPTO_INPUT, new CryptoInputParcel(null, passphrase)); getActivity().setResult(RESULT_OK, mServiceIntent); } else { // also return passphrase back to activity Intent returnIntent = new Intent(); - returnIntent.putExtra(MESSAGE_DATA_PASSPHRASE, passphrase); - returnIntent.putExtra(RESULT_DATA, new CryptoInputParcel(null, passphrase)); + returnIntent.putExtra(RESULT_CRYPTO_INPUT, new CryptoInputParcel(null, passphrase)); getActivity().setResult(RESULT_OK, returnIntent); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index a8a5a1f28..0b22ecdaf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -130,7 +130,7 @@ public abstract class BaseNfcActivity extends BaseActivity { protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_CODE_PASSPHRASE: - CryptoInputParcel input = data.getParcelableExtra(PassphraseDialogActivity.RESULT_DATA); + CryptoInputParcel input = data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT); mPin = input.getPassphrase(); break; -- cgit v1.2.3 From b0a51e7dd30b7f921d575e1e360670cbfed7be6c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 30 Mar 2015 23:39:36 +0200 Subject: remove unused NfcActivity --- .../keychain/ui/EncryptFilesFragment.java | 10 +- .../keychain/ui/NfcActivity.java | 569 --------------------- 2 files changed, 5 insertions(+), 574 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index b320c8a50..7c52798dd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -361,11 +361,6 @@ public class EncryptFilesFragment extends CryptoOperationFragment { return true; } - public void startEncrypt(boolean share) { - mShareAfterEncrypt = share; - cryptoOperation(); - } - public void onEncryptSuccess(final SignEncryptResult result) { if (mDeleteAfterEncrypt) { final Uri[] inputUris = mInputUris.toArray(new Uri[mInputUris.size()]); @@ -472,6 +467,11 @@ public class EncryptFilesFragment extends CryptoOperationFragment { return sendIntent; } + public void startEncrypt(boolean share) { + mShareAfterEncrypt = share; + cryptoOperation(); + } + @Override protected void cryptoOperation(CryptoInputParcel cryptoInput) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java deleted file mode 100644 index 1cb5a41a7..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java +++ /dev/null @@ -1,569 +0,0 @@ -/** - * Copyright (c) 2013-2014 Philipp Jakubeit, Signe Rüsch, Dominik Schürmann - * - * Licensed under the Bouncy Castle License (MIT license). See LICENSE file for details. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.annotation.TargetApi; -import android.app.PendingIntent; -import android.content.Intent; -import android.content.IntentFilter; -import android.nfc.NfcAdapter; -import android.nfc.Tag; -import android.nfc.tech.IsoDep; -import android.os.Build; -import android.os.Bundle; -import android.view.WindowManager; -import android.widget.Toast; - -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.base.BaseActivity; -import org.sufficientlysecure.keychain.util.Iso7816TLV; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * This class provides a communication interface to OpenPGP applications on ISO SmartCard compliant - * NFC devices. - * - * For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf - */ -@TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) -public class NfcActivity extends BaseActivity { - - // actions - public static final String ACTION_SIGN_HASH = "sign_hash"; - public static final String ACTION_DECRYPT_SESSION_KEY = "decrypt_session_key"; - - // always - public static final String EXTRA_KEY_ID = "key_id"; - public static final String EXTRA_PIN = "pin"; - // special extra for OpenPgpService - public static final String EXTRA_DATA = "data"; - - // sign - public static final String EXTRA_NFC_HASH_TO_SIGN = "nfc_hash"; - public static final String EXTRA_NFC_HASH_ALGO = "nfc_hash_algo"; - - // decrypt - public static final String EXTRA_NFC_ENC_SESSION_KEY = "encrypted_session_key"; - - private Intent mServiceIntent; - - private static final int TIMEOUT = 100000; - - private NfcAdapter mNfcAdapter; - private IsoDep mIsoDep; - private String mAction; - - private String mPin; - private Long mKeyId; - - // sign - private byte[] mHashToSign; - private int mHashAlgo; - - // decrypt - private byte[] mEncryptedSessionKey; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Log.d(Constants.TAG, "NfcActivity.onCreate"); - - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - - Intent intent = getIntent(); - Bundle data = intent.getExtras(); - String action = intent.getAction(); - - // if we get are passed a key id, save it for the check - if (data.containsKey(EXTRA_KEY_ID)) { - mKeyId = data.getLong(EXTRA_KEY_ID); - } - - switch (action) { - case ACTION_SIGN_HASH: - mAction = action; - mPin = data.getString(EXTRA_PIN); - mHashToSign = data.getByteArray(EXTRA_NFC_HASH_TO_SIGN); - mHashAlgo = data.getInt(EXTRA_NFC_HASH_ALGO); - mServiceIntent = data.getParcelable(EXTRA_DATA); - - Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); - Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); - Log.d(Constants.TAG, "NfcActivity mHashToSign as hex: " + getHex(mHashToSign)); - Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent); - break; - case ACTION_DECRYPT_SESSION_KEY: - mAction = action; - mPin = data.getString(EXTRA_PIN); - mEncryptedSessionKey = data.getByteArray(EXTRA_NFC_ENC_SESSION_KEY); - mServiceIntent = data.getParcelable(EXTRA_DATA); - - Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); - Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); - Log.d(Constants.TAG, "NfcActivity mEncryptedSessionKey as hex: " + getHex(mEncryptedSessionKey)); - Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent); - break; - case NfcAdapter.ACTION_TAG_DISCOVERED: - Log.e(Constants.TAG, "This should not happen! NfcActivity.onCreate() is being called instead of onNewIntent()!"); - toast("This should not happen! Please create a new bug report that the NFC screen is restarted!"); - finish(); - break; - default: - Log.d(Constants.TAG, "Action not supported: " + action); - break; - } - } - - @Override - protected void initLayout() { - setContentView(R.layout.nfc_activity); - } - - /** - * Called when the system is about to start resuming a previous activity, - * disables NFC Foreground Dispatch - */ - public void onPause() { - super.onPause(); - Log.d(Constants.TAG, "NfcActivity.onPause"); - - disableNfcForegroundDispatch(); - } - - /** - * Called when the activity will start interacting with the user, - * enables NFC Foreground Dispatch - */ - public void onResume() { - super.onResume(); - Log.d(Constants.TAG, "NfcActivity.onResume"); - - enableNfcForegroundDispatch(); - } - - /** - * This activity is started as a singleTop activity. - * All new NFC Intents which are delivered to this activity are handled here - */ - public void onNewIntent(Intent intent) { - if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { - try { - handleNdefDiscoveredIntent(intent); - } catch (IOException e) { - Log.e(Constants.TAG, "Connection error!", e); - toast("Connection Error: " + e.getMessage()); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - } - } - } - - /** Handle NFC communication and return a result. - * - * This method is called by onNewIntent above upon discovery of an NFC tag. - * It handles initialization and login to the application, subsequently - * calls either nfcCalculateSignature() or nfcDecryptSessionKey(), then - * finishes the activity with an appropiate result. - * - * On general communication, see also - * http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_annex-a.aspx - * - * References to pages are generally related to the OpenPGP Application - * on ISO SmartCard Systems specification. - * - */ - private void handleNdefDiscoveredIntent(Intent intent) throws IOException { - - Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); - - // Connect to the detected tag, setting a couple of settings - mIsoDep = IsoDep.get(detectedTag); - mIsoDep.setTimeout(TIMEOUT); // timeout is set to 100 seconds to avoid cancellation during calculation - mIsoDep.connect(); - - // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. - // See specification, page 51 - String accepted = "9000"; - - // Command APDU (page 51) for SELECT FILE command (page 29) - String opening = - "00" // CLA - + "A4" // INS - + "04" // P1 - + "00" // P2 - + "06" // Lc (number of bytes) - + "D27600012401" // Data (6 bytes) - + "00"; // Le - if ( ! card(opening).equals(accepted)) { // activate connection - toast("Opening Error!"); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - return; - } - - // Command APDU for VERIFY command (page 32) - String login = - "00" // CLA - + "20" // INS - + "00" // P1 - + "82" // P2 (PW1) - + String.format("%02x", mPin.length()) // Lc - + Hex.toHexString(mPin.getBytes()); - if ( ! card(login).equals(accepted)) { // login - toast("Wrong PIN!"); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - return; - } - - if (ACTION_SIGN_HASH.equals(mAction)) { - - // If we were supplied with a key id for checking, do so - if (mKeyId != null) { - // For signing, we check the master key - long keyId = nfcGetKeyId(mIsoDep, 0); - // If it's wrong, just cancel - if (keyId != mKeyId) { - toast("NFC Tag has wrong signing key id!"); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - return; - } - } - - // returns signed hash - byte[] signedHash = nfcCalculateSignature(mHashToSign, mHashAlgo); - - if (signedHash == null) { - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - return; - } - - Log.d(Constants.TAG, "NfcActivity signedHash as hex: " + getHex(signedHash)); - - // give data through for new service call - // OpenPgpApi.EXTRA_NFC_SIGNED_HASH - mServiceIntent.putExtra("nfc_signed_hash", signedHash); - setResult(RESULT_OK, mServiceIntent); - finish(); - - } else if (ACTION_DECRYPT_SESSION_KEY.equals(mAction)) { - - // If we were supplied with a key id for checking, do so - if (mKeyId != null) { - // For decryption, we check the confidentiality key - long keyId = nfcGetKeyId(mIsoDep, 1); - // If it's wrong, just cancel - if (keyId != mKeyId) { - toast("NFC Tag has wrong encryption key id!"); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - return; - } - } - - byte[] decryptedSessionKey = nfcDecryptSessionKey(mEncryptedSessionKey); - - // give data through for new service call - // OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY - mServiceIntent.putExtra("nfc_decrypted_session_key", decryptedSessionKey); - setResult(RESULT_OK, mServiceIntent); - finish(); - } - - } - - /** - * Gets the user ID - * - * @return the user id as "name " - * @throws java.io.IOException - */ - public String getUserId() throws IOException { - String info = "00CA006500"; - String data = "00CA005E00"; - return getName(card(info)) + " <" + (new String(Hex.decode(getDataField(card(data))))) + ">"; - } - - /** Return the key id from application specific data stored on tag, or null - * if it doesn't exist. - * - * @param idx Index of the key to return the fingerprint from. - * @return The long key id of the requested key, or null if not found. - */ - public static Long nfcGetKeyId(IsoDep isoDep, int idx) throws IOException { - byte[] fp = nfcGetFingerprint(isoDep, idx); - if (fp == null) { - return null; - } - ByteBuffer buf = ByteBuffer.wrap(fp); - // skip first 12 bytes of the fingerprint - buf.position(12); - // the last eight bytes are the key id (big endian, which is default order in ByteBuffer) - return buf.getLong(); - } - - /** Return fingerprints of all keys from application specific data stored - * on tag, or null if data not available. - * - * @return The fingerprints of all subkeys in a contiguous byte array. - */ - public static byte[] nfcGetFingerprints(IsoDep isoDep) throws IOException { - String data = "00CA006E00"; - byte[] buf = isoDep.transceive(Hex.decode(data)); - - Iso7816TLV tlv = Iso7816TLV.readSingle(buf, true); - Log.d(Constants.TAG, "nfc tlv data:\n" + tlv.prettyPrint()); - - Iso7816TLV fptlv = Iso7816TLV.findRecursive(tlv, 0xc5); - if (fptlv == null) { - return null; - } - - return fptlv.mV; - } - - /** Return the fingerprint from application specific data stored on tag, or - * null if it doesn't exist. - * - * @param idx Index of the key to return the fingerprint from. - * @return The fingerprint of the requested key, or null if not found. - */ - public static byte[] nfcGetFingerprint(IsoDep isoDep, int idx) throws IOException { - byte[] data = nfcGetFingerprints(isoDep); - - // return the master key fingerprint - ByteBuffer fpbuf = ByteBuffer.wrap(data); - byte[] fp = new byte[20]; - fpbuf.position(idx*20); - fpbuf.get(fp, 0, 20); - - return fp; - } - - /** - * Calls to calculate the signature and returns the MPI value - * - * @param hash the hash for signing - * @return a big integer representing the MPI for the given hash - * @throws java.io.IOException - */ - public byte[] nfcCalculateSignature(byte[] hash, int hashAlgo) throws IOException { - - // dsi, including Lc - String dsi; - - Log.i(Constants.TAG, "Hash: " + hashAlgo); - switch (hashAlgo) { - case HashAlgorithmTags.SHA1: - if (hash.length != 20) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 10!"); - } - dsi = "23" // Lc - + "3021" // Tag/Length of Sequence, the 0x21 includes all following 33 bytes - + "3009" // Tag/Length of Sequence, the 0x09 are the following header bytes - + "0605" + "2B0E03021A" // OID of SHA1 - + "0500" // TLV coding of ZERO - + "0414" + getHex(hash); // 0x14 are 20 hash bytes - break; - case HashAlgorithmTags.RIPEMD160: - if (hash.length != 20) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 20!"); - } - dsi = "233021300906052B2403020105000414" + getHex(hash); - break; - case HashAlgorithmTags.SHA224: - if (hash.length != 28) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 28!"); - } - dsi = "2F302D300D06096086480165030402040500041C" + getHex(hash); - break; - case HashAlgorithmTags.SHA256: - if (hash.length != 32) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 32!"); - } - dsi = "333031300D060960864801650304020105000420" + getHex(hash); - break; - case HashAlgorithmTags.SHA384: - if (hash.length != 48) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 48!"); - } - dsi = "433041300D060960864801650304020205000430" + getHex(hash); - break; - case HashAlgorithmTags.SHA512: - if (hash.length != 64) { - throw new RuntimeException("Bad hash length (" + hash.length + ", expected 64!"); - } - dsi = "533051300D060960864801650304020305000440" + getHex(hash); - break; - default: - throw new RuntimeException("Not supported hash algo!"); - } - - // Command APDU for PERFORM SECURITY OPERATION: COMPUTE DIGITAL SIGNATURE (page 37) - String apdu = - "002A9E9A" // CLA, INS, P1, P2 - + dsi // digital signature input - + "00"; // Le - - String response = card(apdu); - - // split up response into signature and status - String status = response.substring(response.length()-4); - String signature = response.substring(0, response.length() - 4); - - // while we are getting 0x61 status codes, retrieve more data - while (status.substring(0, 2).equals("61")) { - Log.d(Constants.TAG, "requesting more data, status " + status); - // Send GET RESPONSE command - response = card("00C00000" + status.substring(2)); - status = response.substring(response.length()-4); - signature += response.substring(0, response.length()-4); - } - - Log.d(Constants.TAG, "final response:" + status); - - if ( ! status.equals("9000")) { - toast("Bad NFC response code: " + status); - return null; - } - - // Make sure the signature we received is actually the expected number of bytes long! - if (signature.length() != 256 && signature.length() != 512) { - toast("Bad signature length! Expected 128 or 256 bytes, got " + signature.length() / 2); - return null; - } - - return Hex.decode(signature); - } - - /** - * Calls to calculate the signature and returns the MPI value - * - * @param encryptedSessionKey the encoded session key - * @return the decoded session key - * @throws java.io.IOException - */ - public byte[] nfcDecryptSessionKey(byte[] encryptedSessionKey) throws IOException { - String firstApdu = "102a8086fe"; - String secondApdu = "002a808603"; - String le = "00"; - - byte[] one = new byte[254]; - // leave out first byte: - System.arraycopy(encryptedSessionKey, 1, one, 0, one.length); - - byte[] two = new byte[encryptedSessionKey.length - 1 - one.length]; - for (int i = 0; i < two.length; i++) { - two[i] = encryptedSessionKey[i + one.length + 1]; - } - - String first = card(firstApdu + getHex(one)); - String second = card(secondApdu + getHex(two) + le); - - String decryptedSessionKey = getDataField(second); - - Log.d(Constants.TAG, "decryptedSessionKey: " + decryptedSessionKey); - - return Hex.decode(decryptedSessionKey); - } - - /** - * Prints a message to the screen - * - * @param text the text which should be contained within the toast - */ - private void toast(String text) { - Toast.makeText(this, text, Toast.LENGTH_LONG).show(); - } - - /** - * Receive new NFC Intents to this activity only by enabling foreground dispatch. - * This can only be done in onResume! - */ - public void enableNfcForegroundDispatch() { - mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - Intent nfcI = new Intent(this, NfcActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); - PendingIntent nfcPendingIntent = PendingIntent.getActivity(this, 0, nfcI, PendingIntent.FLAG_CANCEL_CURRENT); - IntentFilter[] writeTagFilters = new IntentFilter[]{ - new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED) - }; - - // https://code.google.com/p/android/issues/detail?id=62918 - // maybe mNfcAdapter.enableReaderMode(); ? - try { - mNfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null); - } catch (IllegalStateException e) { - Log.i(Constants.TAG, "NfcForegroundDispatch Error!", e); - } - Log.d(Constants.TAG, "NfcForegroundDispatch has been enabled!"); - } - - /** - * Disable foreground dispatch in onPause! - */ - public void disableNfcForegroundDispatch() { - mNfcAdapter.disableForegroundDispatch(this); - Log.d(Constants.TAG, "NfcForegroundDispatch has been disabled!"); - } - - /** - * Gets the name of the user out of the raw card output regarding card holder related data - * - * @param name the raw card holder related data from the card - * @return the name given in this data - */ - public String getName(String name) { - String slength; - int ilength; - name = name.substring(6); - slength = name.substring(0, 2); - ilength = Integer.parseInt(slength, 16) * 2; - name = name.substring(2, ilength + 2); - name = (new String(Hex.decode(name))).replace('<', ' '); - return (name); - } - - /** - * Reduces the raw data from the card by four characters - * - * @param output the raw data from the card - * @return the data field of that data - */ - private String getDataField(String output) { - return output.substring(0, output.length() - 4); - } - - /** - * Communicates with the OpenPgpCard via the APDU - * - * @param hex the hexadecimal APDU - * @return The answer from the card - * @throws java.io.IOException throws an exception if something goes wrong - */ - public String card(String hex) throws IOException { - return getHex(mIsoDep.transceive(Hex.decode(hex))); - } - - /** - * Converts a byte array into an hex string - * - * @param raw the byte array representation - * @return the hexadecimal string representation - */ - public static String getHex(byte[] raw) { - return new String(Hex.encode(raw)); - } -} -- cgit v1.2.3 From aea52f2e6f5463b0a957a36a14604d56b342069c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 31 Mar 2015 00:24:08 +0200 Subject: Simplify passphrase dialog design --- .../org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index c1771ce57..c75e188a8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -191,7 +191,8 @@ public class PassphraseDialogActivity extends FragmentActivity { CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); - alert.setTitle(R.string.title_unlock); + // No title, see http://www.google.com/design/spec/components/dialogs.html#dialogs-alerts + //alert.setTitle() LayoutInflater inflater = LayoutInflater.from(theme); View view = inflater.inflate(R.layout.passphrase_dialog, null); @@ -319,7 +320,7 @@ public class PassphraseDialogActivity extends FragmentActivity { AlertDialog dialog = alert.create(); dialog.setButton(DialogInterface.BUTTON_POSITIVE, - activity.getString(android.R.string.ok), (DialogInterface.OnClickListener) null); + activity.getString(R.string.btn_unlock), (DialogInterface.OnClickListener) null); return dialog; } -- cgit v1.2.3 From 8bd8267a47bbc86fc534858be68de43e9ecb8eec Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 31 Mar 2015 00:28:24 +0200 Subject: work on passphrase data flow --- .../sufficientlysecure/keychain/ui/CryptoOperationFragment.java | 9 +++++++++ .../sufficientlysecure/keychain/ui/PassphraseDialogActivity.java | 3 +-- .../org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java | 6 ++++++ 3 files changed, 16 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java index b632509bb..f0a7859f7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java @@ -62,6 +62,11 @@ public abstract class CryptoOperationFragment extends Fragment { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == Activity.RESULT_CANCELED) { + onCryptoOperationCancelled(); + return; + } + switch (requestCode) { case REQUEST_CODE_PASSPHRASE: { if (resultCode == Activity.RESULT_OK && data != null) { @@ -116,4 +121,8 @@ public abstract class CryptoOperationFragment extends Fragment { protected abstract void cryptoOperation(CryptoInputParcel cryptoInput); + protected void onCryptoOperationCancelled() { + // Nothing to do here, in most cases + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index c1771ce57..02500df65 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -253,8 +253,7 @@ public class PassphraseDialogActivity extends FragmentActivity { message = getString(R.string.yubikey_pin_for, userId); break; default: - message = "This should not happen!"; - break; + throw new AssertionError("Unhandled SecretKeyType (should not happen)"); } } catch (ProviderHelper.NotFoundException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index 0b22ecdaf..9b10ccdb1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -4,6 +4,7 @@ package org.sufficientlysecure.keychain.ui.base; import java.io.IOException; import java.nio.ByteBuffer; +import android.app.Activity; import android.app.PendingIntent; import android.content.Intent; import android.content.IntentFilter; @@ -130,6 +131,11 @@ public abstract class BaseNfcActivity extends BaseActivity { protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_CODE_PASSPHRASE: + if (resultCode != Activity.RESULT_OK) { + setResult(resultCode); + finish(); + return; + } CryptoInputParcel input = data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT); mPin = input.getPassphrase(); break; -- cgit v1.2.3 From c37e7ef2410cc09cf880f6c85168605c70d5d691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 31 Mar 2015 01:53:37 +0200 Subject: Better check if file is already added --- .../keychain/ui/EncryptFilesFragment.java | 61 +++++++++++++++------- 1 file changed, 42 insertions(+), 19 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 1a67bc8dd..f85bd707b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui; import android.app.Activity; import android.app.ProgressDialog; +import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Point; @@ -62,6 +63,7 @@ import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.ShareHelper; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -194,14 +196,14 @@ public class EncryptFilesFragment extends CryptoOperationFragment { return; } - if (mFilesAdapter.getAsArrayList().contains(inputUri)) { + try { + mFilesAdapter.add(inputUri); + } catch (IOException e) { Notify.create(getActivity(), getActivity().getString(R.string.error_file_added_already, FileHelper.getFilename(getActivity(), inputUri)), Notify.Style.ERROR).show(); return; } - - mFilesAdapter.add(inputUri); mSelectedFiles.requestFocus(); } @@ -428,7 +430,6 @@ public class EncryptFilesFragment extends CryptoOperationFragment { } else { data.setEncryptionMasterKeyIds(mEncryptionKeyIds); data.setSignatureMasterKeyId(mSigningKeyId); -// data.setSignaturePassphrase(mSigningKeyPassphrase); } return data; } @@ -578,11 +579,32 @@ public class EncryptFilesFragment extends CryptoOperationFragment { String filename; long fileSize; - ViewModel(Uri inputUri, Bitmap thumbnail, String filename, long fileSize) { + ViewModel(Context context, Uri inputUri) { this.inputUri = inputUri; - this.thumbnail = thumbnail; - this.filename = filename; - this.fileSize = fileSize; + int px = FormattingUtils.dpToPx(context, 48); + this.thumbnail = FileHelper.getThumbnail(context, inputUri, new Point(px, px)); + this.filename = FileHelper.getFilename(context, inputUri); + this.fileSize = FileHelper.getFileSize(context, inputUri); + } + + /** + * Depends on inputUri only + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ViewModel viewModel = (ViewModel) o; + return !(inputUri != null ? !inputUri.equals(viewModel.inputUri) + : viewModel.inputUri != null); + } + + /** + * Depends on inputUri only + */ + @Override + public int hashCode() { + return inputUri != null ? inputUri.hashCode() : 0; } @Override @@ -691,28 +713,29 @@ public class EncryptFilesFragment extends CryptoOperationFragment { return position == mDataset.size(); } - public void add(Uri inputUri) { - mDataset.add(createModel(inputUri)); + public void add(Uri inputUri) throws IOException { + ViewModel newModel = new ViewModel(mActivity, inputUri); + if (mDataset.contains(newModel)) { + throw new IOException("Already added!"); + } + mDataset.add(newModel); notifyItemInserted(mDataset.size() - 1); } public void addAll(ArrayList inputUris) { if (inputUris != null) { for (Uri inputUri : inputUris) { - mDataset.add(createModel(inputUri)); + ViewModel newModel = new ViewModel(mActivity, inputUri); + if (mDataset.contains(newModel)) { + Log.e(Constants.TAG, "Skipped duplicate " + inputUri.toString()); + } else { + mDataset.add(newModel); + } } } // TODO: notifyItemInserted? } - private ViewModel createModel(Uri inputUri) { - int px = FormattingUtils.dpToPx(mActivity, 48); - Bitmap thumbnail = FileHelper.getThumbnail(mActivity, inputUri, new Point(px, px)); - String filename = FileHelper.getFilename(mActivity, inputUri); - long size = FileHelper.getFileSize(mActivity, inputUri); - return new ViewModel(inputUri, thumbnail, filename, size); - } - public void remove(ViewModel model) { int position = mDataset.indexOf(model); mDataset.remove(position); -- cgit v1.2.3 From cc44ff1a8b3b51331023ef738ccd28bece32da40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 31 Mar 2015 15:44:37 +0200 Subject: Prepare decrypt UI for input parcel --- .../keychain/ui/DecryptFilesFragment.java | 168 +++++++-------------- .../keychain/ui/DecryptTextFragment.java | 14 +- 2 files changed, 58 insertions(+), 124 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java index d1c005868..cd66902ba 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java @@ -17,6 +17,7 @@ package org.sufficientlysecure.keychain.ui; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; @@ -32,7 +33,6 @@ import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.TextView; -import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; @@ -64,6 +64,8 @@ public class DecryptFilesFragment extends DecryptFragment { private Uri mInputUri = null; private Uri mOutputUri = null; + private String mCurrentCryptoOperation; + /** * Creates new instance of this fragment */ @@ -145,7 +147,7 @@ public class DecryptFilesFragment extends DecryptFragment { return; } -// decryptOriginalFilename(); + startDecryptFilenames(); } private String removeEncryptedAppend(String name) { @@ -158,121 +160,45 @@ public class DecryptFilesFragment extends DecryptFragment { } private void askForOutputFilename(String originalFilename) { - String targetName; - if (!TextUtils.isEmpty(originalFilename)) { - targetName = originalFilename; - } else { - targetName = removeEncryptedAppend(FileHelper.getFilename(getActivity(), mInputUri)); + if (TextUtils.isEmpty(originalFilename)) { + originalFilename = removeEncryptedAppend(FileHelper.getFilename(getActivity(), mInputUri)); } + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { File file = new File(mInputUri.getPath()); File parentDir = file.exists() ? file.getParentFile() : Constants.Path.APP_DIR; - File targetFile = new File(parentDir, targetName); + File targetFile = new File(parentDir, originalFilename); FileHelper.saveFile(this, getString(R.string.title_decrypt_to_file), getString(R.string.specify_file_to_decrypt_to), targetFile, REQUEST_CODE_OUTPUT); } else { - FileHelper.saveDocument(this, "*/*", targetName, REQUEST_CODE_OUTPUT); + FileHelper.saveDocument(this, "*/*", originalFilename, REQUEST_CODE_OUTPUT); } } + private void startDecrypt() { + mCurrentCryptoOperation = KeychainIntentService.ACTION_DECRYPT_VERIFY; + cryptoOperation(new CryptoInputParcel()); + } - // TODO: also needs to use cryptoOperation!!! (switch between this and normal decrypt -// private void decryptOriginalFilename() { -// Log.d(Constants.TAG, "decryptOriginalFilename"); -// -// Intent intent = new Intent(getActivity(), KeychainIntentService.class); -// -// // fill values for this action -// Bundle data = new Bundle(); -// intent.setAction(KeychainIntentService.ACTION_DECRYPT_METADATA); -// -// // data -// Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri); -// -// data.putInt(KeychainIntentService.SOURCE, IOType.URI.ordinal()); -// data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_INPUT_URI, mInputUri); -// -// data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal()); -// data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri); -// -// data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); -// data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); -// -// intent.putExtra(KeychainIntentService.EXTRA_SERVICE_INTENT, data); -// -// // Message is received after decrypting is done in KeychainIntentService -// ServiceProgressHandler saveHandler = new ServiceProgressHandler( -// getActivity(), -// getString(R.string.progress_decrypting), -// ProgressDialog.STYLE_HORIZONTAL, -// ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) { -// public void handleMessage(Message message) { -// // handle messages by standard KeychainIntentServiceHandler first -// super.handleMessage(message); -// -// // handle pending messages -// if (handlePendingMessage(message)) { -// return; -// } -// -// if (message.arg1 == MessageStatus.OKAY.ordinal()) { -// // get returned data bundle -// Bundle returnData = message.getData(); -// -// DecryptVerifyResult pgpResult = -// returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); -// -// if (pgpResult.isPending()) { -// if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == -// DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { -// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); -// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == -// DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { -// startPassphraseDialog(Constants.key.symmetric); -// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == -// DecryptVerifyResult.RESULT_PENDING_NFC) { -// startNfcDecrypt(pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); -// } else { -// throw new RuntimeException("Unhandled pending result!"); -// } -// } else if (pgpResult.success()) { -// // go on... -// askForOutputFilename(pgpResult.getDecryptMetadata().getFilename()); -// } else { -// pgpResult.createNotify(getActivity()).show(); -// } -// } -// } -// }; -// -// // Create a new Messenger for the communication back -// Messenger messenger = new Messenger(saveHandler); -// intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); -// -// // show progress dialog -// saveHandler.showProgressDialog(getActivity()); -// -// // start service with intent -// getActivity().startService(intent); -// } - - private void decryptStart() { + private void startDecryptFilenames() { + mCurrentCryptoOperation = KeychainIntentService.ACTION_DECRYPT_METADATA; cryptoOperation(new CryptoInputParcel()); } @Override + @SuppressLint("HandlerLeak") protected void cryptoOperation(CryptoInputParcel cryptoInput) { - Log.d(Constants.TAG, "decryptStart"); - // Send all information needed to service to decrypt in other thread Intent intent = new Intent(getActivity(), KeychainIntentService.class); // fill values for this action Bundle data = new Bundle(); - - intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY); + // use current operation, either decrypt metadata or decrypt payload + intent.setAction(mCurrentCryptoOperation); // data + data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); + Log.d(Constants.TAG, "mInputUri=" + mInputUri + ", mOutputUri=" + mOutputUri); data.putInt(KeychainIntentService.SOURCE, IOType.URI.ordinal()); @@ -281,8 +207,8 @@ public class DecryptFilesFragment extends DecryptFragment { data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal()); data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri); - data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); - data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); +// data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); +// data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -292,6 +218,7 @@ public class DecryptFilesFragment extends DecryptFragment { getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL, ProgressDialogFragment.ServiceType.KEYCHAIN_INTENT) { + @Override public void handleMessage(Message message) { // handle messages by standard KeychainIntentServiceHandler first super.handleMessage(message); @@ -324,24 +251,37 @@ public class DecryptFilesFragment extends DecryptFragment { if (pgpResult.success()) { - // display signature result in activity - onResult(pgpResult); - - if (mDeleteAfter.isChecked()) { - // Create and show dialog to delete original file - DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri); - deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog"); - setInputUri(null); - } - - /* - // A future open after decryption feature - if () { - Intent viewFile = new Intent(Intent.ACTION_VIEW); - viewFile.setInputData(mOutputUri); - startActivity(viewFile); + switch (mCurrentCryptoOperation) { + case KeychainIntentService.ACTION_DECRYPT_METADATA: { + askForOutputFilename(pgpResult.getDecryptMetadata().getFilename()); + break; + } + case KeychainIntentService.ACTION_DECRYPT_VERIFY: { + // display signature result in activity + onResult(pgpResult); + + if (mDeleteAfter.isChecked()) { + // Create and show dialog to delete original file + DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(mInputUri); + deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog"); + setInputUri(null); + } + + /* + // A future open after decryption feature + if () { + Intent viewFile = new Intent(Intent.ACTION_VIEW); + viewFile.setInputData(mOutputUri); + startActivity(viewFile); + } + */ + break; + } + default: { + Log.e(Constants.TAG, "Bug: not supported operation!"); + break; + } } - */ } else { pgpResult.createNotify(getActivity()).show(); } @@ -391,7 +331,7 @@ public class DecryptFilesFragment extends DecryptFragment { // This happens after output file was selected, so start our operation if (resultCode == Activity.RESULT_OK && data != null) { mOutputUri = data.getData(); - decryptStart(); + startDecrypt(); } return; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index 523b24fd7..086830389 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -144,19 +144,12 @@ public class DecryptTextFragment extends DecryptFragment { String ciphertext = getArguments().getString(ARG_CIPHERTEXT); if (ciphertext != null) { mCiphertext = ciphertext; - decryptStart(); + cryptoOperation(new CryptoInputParcel()); } } - private void decryptStart() { - cryptoOperation(new CryptoInputParcel()); - } - @Override protected void cryptoOperation(CryptoInputParcel cryptoInput) { - - Log.d(Constants.TAG, "decryptStart"); - // Send all information needed to service to decrypt in other thread Intent intent = new Intent(getActivity(), KeychainIntentService.class); @@ -166,10 +159,11 @@ public class DecryptTextFragment extends DecryptFragment { intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY); // data + data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); data.putInt(KeychainIntentService.TARGET, IOType.BYTES.ordinal()); data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes()); - data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); - data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); +// data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); +// data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); -- cgit v1.2.3 From ad69622b6983d139e2cef1380f502edef19d2180 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 1 Apr 2015 00:38:01 +0200 Subject: fix Decrypt*Fragment for RequiredInputParcel (except decryptOriginalFilename) --- .../keychain/ui/CryptoOperationFragment.java | 3 +- .../keychain/ui/DecryptFilesFragment.java | 36 +----------- .../keychain/ui/DecryptFragment.java | 10 ---- .../keychain/ui/DecryptTextFragment.java | 66 ++++------------------ .../keychain/ui/PassphraseDialogActivity.java | 15 ++++- 5 files changed, 25 insertions(+), 105 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java index f0a7859f7..b136492b4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java @@ -49,7 +49,8 @@ public abstract class CryptoOperationFragment extends Fragment { return; } - case PASSPHRASE: { + case PASSPHRASE: + case PASSPHRASE_SYMMETRIC: { Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput); startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java index cd66902ba..766e65e8b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java @@ -93,9 +93,6 @@ public class DecryptFilesFragment extends DecryptFragment { mDecryptButton = view.findViewById(R.id.decrypt_file_action_decrypt); view.findViewById(R.id.decrypt_file_browse).setOnClickListener(new View.OnClickListener() { public void onClick(View v) { - // reset state - mPassphrase = null; - mNfcDecryptedSessionKey = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { FileHelper.openDocument(DecryptFilesFragment.this, "*/*", REQUEST_CODE_INPUT); } else { @@ -207,8 +204,7 @@ public class DecryptFilesFragment extends DecryptFragment { data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal()); data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri); -// data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); -// data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); + data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -235,20 +231,6 @@ public class DecryptFilesFragment extends DecryptFragment { DecryptVerifyResult pgpResult = returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); -// if (pgpResult.isPending()) { -// if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == -// DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { -// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); -// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == -// DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { -// startPassphraseDialog(Constants.key.symmetric); -// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == -// DecryptVerifyResult.RESULT_PENDING_NFC) { -// startNfcDecrypt(pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); -// } else { -// throw new RuntimeException("Unhandled pending result!"); -// } - if (pgpResult.success()) { switch (mCurrentCryptoOperation) { @@ -304,22 +286,6 @@ public class DecryptFilesFragment extends DecryptFragment { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { -// case REQUEST_CODE_PASSPHRASE: { -// if (resultCode == Activity.RESULT_OK && data != null) { -// mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); -//// decryptOriginalFilename(); -// } -// return; -// } -// -// case REQUEST_CODE_NFC_DECRYPT: { -// if (resultCode == Activity.RESULT_OK && data != null) { -// mNfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); -//// decryptOriginalFilename(); -// } -// return; -// } - case REQUEST_CODE_INPUT: { if (resultCode == Activity.RESULT_OK && data != null) { setInputUri(data.getData()); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index 38ad54ad3..f320a6d84 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.Fragment; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; @@ -32,14 +31,10 @@ import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; -import org.sufficientlysecure.keychain.util.Passphrase; public abstract class DecryptFragment extends CryptoOperationFragment { private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006; -// public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; -// public static final int REQUEST_CODE_NFC_DECRYPT = 0x00008002; - protected long mSignatureKeyId = 0; protected LinearLayout mResultLayout; @@ -56,11 +51,6 @@ public abstract class DecryptFragment extends CryptoOperationFragment { protected TextView mSignatureEmail; protected TextView mSignatureAction; - - // State - protected Passphrase mPassphrase; - protected byte[] mNfcDecryptedSessionKey; - @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index 086830389..9c6c89c43 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -17,7 +17,6 @@ package org.sufficientlysecure.keychain.ui; -import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; @@ -30,7 +29,6 @@ import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; -import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; @@ -52,10 +50,7 @@ public class DecryptTextFragment extends DecryptFragment { // view private LinearLayout mValidLayout; private LinearLayout mInvalidLayout; - private Button mInvalidButton; private TextView mText; - private View mShareButton; - private View mCopyButton; // model private String mCiphertext; @@ -82,23 +77,26 @@ public class DecryptTextFragment extends DecryptFragment { View view = inflater.inflate(R.layout.decrypt_text_fragment, container, false); mValidLayout = (LinearLayout) view.findViewById(R.id.decrypt_text_valid); mInvalidLayout = (LinearLayout) view.findViewById(R.id.decrypt_text_invalid); - mInvalidButton = (Button) view.findViewById(R.id.decrypt_text_invalid_button); mText = (TextView) view.findViewById(R.id.decrypt_text_plaintext); - mShareButton = view.findViewById(R.id.action_decrypt_share_plaintext); - mCopyButton = view.findViewById(R.id.action_decrypt_copy_plaintext); - mShareButton.setOnClickListener(new View.OnClickListener() { + + View vShareButton = view.findViewById(R.id.action_decrypt_share_plaintext); + vShareButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(sendWithChooserExcludingEncrypt(mText.getText().toString())); } }); - mCopyButton.setOnClickListener(new View.OnClickListener() { + + View vCopyButton = view.findViewById(R.id.action_decrypt_copy_plaintext); + vCopyButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { copyToClipboard(mText.getText().toString()); } }); - mInvalidButton.setOnClickListener(new View.OnClickListener() { + + Button vInvalidButton = (Button) view.findViewById(R.id.decrypt_text_invalid_button); + vInvalidButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mInvalidLayout.setVisibility(View.GONE); @@ -162,8 +160,7 @@ public class DecryptTextFragment extends DecryptFragment { data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); data.putInt(KeychainIntentService.TARGET, IOType.BYTES.ordinal()); data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes()); -// data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); -// data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); + data.putParcelable(KeychainIntentService.EXTRA_CRYPTO_INPUT, cryptoInput); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -189,19 +186,6 @@ public class DecryptTextFragment extends DecryptFragment { DecryptVerifyResult pgpResult = returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); -// if (pgpResult.isPending()) { -// if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == -// DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { -// startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); -// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == -// DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { -// startPassphraseDialog(Constants.key.symmetric); -// } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == -// DecryptVerifyResult.RESULT_PENDING_NFC) { -// startNfcDecrypt(pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); -// } else { -// throw new RuntimeException("Unhandled pending result!"); -// } if (pgpResult.success()) { byte[] decryptedMessage = returnData @@ -250,34 +234,4 @@ public class DecryptTextFragment extends DecryptFragment { getActivity().startService(intent); } -// @Override -// public void onActivityResult(int requestCode, int resultCode, Intent data) { -// switch (requestCode) { -// -// case REQUEST_CODE_PASSPHRASE: { -// if (resultCode == Activity.RESULT_OK && data != null) { -// mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); -// decryptStart(); -// } else { -// getActivity().finish(); -// } -// return; -// } -// -// case REQUEST_CODE_NFC_DECRYPT: { -// if (resultCode == Activity.RESULT_OK && data != null) { -// mNfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); -// decryptStart(); -// } else { -// getActivity().finish(); -// } -// return; -// } -// -// default: { -// super.onActivityResult(requestCode, resultCode, data); -// } -// } -// } - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index 074e40b22..007608f80 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -97,10 +97,19 @@ public class PassphraseDialogActivity extends FragmentActivity { keyId = getIntent().getLongExtra(EXTRA_SUBKEY_ID, 0); } else { RequiredInputParcel requiredInput = getIntent().getParcelableExtra(EXTRA_REQUIRED_INPUT); - if (requiredInput.mType != RequiredInputType.PASSPHRASE) { - throw new AssertionError("Wrong required input type for PassphraseDialogActivity!"); + switch (requiredInput.mType) { + case PASSPHRASE_SYMMETRIC: { + keyId = Constants.key.symmetric; + break; + } + case PASSPHRASE: { + keyId = requiredInput.getSubKeyId(); + break; + } + default: { + throw new AssertionError("Unsupported required input type for PassphraseDialogActivity!"); + } } - keyId = requiredInput.getSubKeyId(); } Intent serviceIntent = getIntent().getParcelableExtra(EXTRA_SERVICE_INTENT); -- cgit v1.2.3 From 8e5d0d1682bf0478b2df8e44c6d184a14cbd4ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 4 Apr 2015 19:01:03 +0200 Subject: Fix nullpointer with Intent API, fix clearing of encrypt file list, notify when adding a range of input uris --- .../org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java | 5 ++--- .../org/sufficientlysecure/keychain/ui/EncryptTextFragment.java | 8 +++++--- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index f85bd707b..ddced7cce 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -390,8 +390,6 @@ public class EncryptFilesFragment extends CryptoOperationFragment { }); deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog"); - - mFilesModels.clear(); } else { if (mShareAfterEncrypt) { // Share encrypted message/file @@ -724,6 +722,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { public void addAll(ArrayList inputUris) { if (inputUris != null) { + int startIndex = mDataset.size(); for (Uri inputUri : inputUris) { ViewModel newModel = new ViewModel(mActivity, inputUri); if (mDataset.contains(newModel)) { @@ -732,8 +731,8 @@ public class EncryptFilesFragment extends CryptoOperationFragment { mDataset.add(newModel); } } + notifyItemRangeInserted(startIndex, mDataset.size() - startIndex); } - // TODO: notifyItemInserted? } public void remove(ViewModel model) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index fecc9ef52..47645099d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -123,9 +123,6 @@ public class EncryptTextFragment extends CryptoOperationFragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.encrypt_text_fragment, container, false); - if (mMessage != null) { - mText.setText(mMessage); - } mText = (TextView) view.findViewById(R.id.encrypt_text_text); mText.addTextChangedListener(new TextWatcher() { @Override @@ -144,6 +141,11 @@ public class EncryptTextFragment extends CryptoOperationFragment { } }); + // set initial text + if (mMessage != null) { + mText.setText(mMessage); + } + return view; } -- cgit v1.2.3 From 13332bc28dd0d85c28c9f66b2d871aac68293db0 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Tue, 7 Apr 2015 22:59:31 +0530 Subject: linked system contact auto-refresh added, fixed contact image issue --- .../keychain/ui/ViewKeyFragment.java | 90 +++++++++++++++++----- 1 file changed, 70 insertions(+), 20 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java index c3a8d60f8..ce353f82e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java @@ -55,7 +55,6 @@ public class ViewKeyFragment extends LoaderFragment implements //private ListView mLinkedSystemContact; boolean mIsSecret = false; - boolean mSystemContactLoaded = false; LinearLayout mSystemContactLayout; ImageView mSystemContactPicture; @@ -63,6 +62,12 @@ public class ViewKeyFragment extends LoaderFragment implements private static final int LOADER_ID_UNIFIED = 0; private static final int LOADER_ID_USER_IDS = 1; + private static final int LOADER_ID_LINKED_CONTACT = 2; + + private static final String LOADER_LINKED_CONTACT_MASTER_KEY_ID + = "loader_linked_contact_master_key_id"; + private static final String LOADER_LINKED_CONTACT_IS_SECRET + = "loader_linked_contact_is_secret"; private UserIdsAdapter mUserIdsAdapter; @@ -119,28 +124,25 @@ public class ViewKeyFragment extends LoaderFragment implements } /** - * Checks if a system contact exists for given masterKeyId, and if it does, sets name, picture - * and onClickListener for the linked system contact's layout - * In the case of a secret key, "me" contact details are loaded + * Expects to be called only if a linked system contact exists. Sets name, picture + * and onClickListener for the linked system contact's layout. + * In the case of a secret key, "me" contact details are loaded. * - * @param masterKeyId + * @param contactId */ - private void loadLinkedSystemContact(final long masterKeyId) { + private void loadLinkedSystemContact(final long contactId) { + final Context context = mSystemContactName.getContext(); final ContentResolver resolver = context.getContentResolver(); - long contactId; String contactName = null; if (mIsSecret) {//all secret keys are linked to "me" profile in contacts - contactId = ContactHelper.getMainProfileContactId(resolver); List mainProfileNames = ContactHelper.getMainProfileContactName(context); if (mainProfileNames != null && mainProfileNames.size() > 0) { contactName = mainProfileNames.get(0); } - } else { - contactId = ContactHelper.findContactId(resolver, masterKeyId); contactName = ContactHelper.getContactName(resolver, contactId); } @@ -151,18 +153,16 @@ public class ViewKeyFragment extends LoaderFragment implements if (mIsSecret) { picture = ContactHelper.loadMainProfilePhoto(resolver, false); } else { - picture = ContactHelper.loadPhotoByMasterKeyId(resolver, masterKeyId, false); + picture = ContactHelper.loadPhotoByContactId(resolver, contactId, false); } if (picture != null) mSystemContactPicture.setImageBitmap(picture); - final long finalContactId = contactId; mSystemContactLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - launchContactActivity(finalContactId, context); + launchContactActivity(contactId, context); } }); - mSystemContactLoaded = true; } } @@ -195,7 +195,6 @@ public class ViewKeyFragment extends LoaderFragment implements loadData(dataUri); } - // These are the rows that we will retrieve. static final String[] UNIFIED_PROJECTION = new String[]{ KeychainContract.KeyRings._ID, @@ -218,6 +217,12 @@ public class ViewKeyFragment extends LoaderFragment implements static final int INDEX_FINGERPRINT = 7; static final int INDEX_HAS_ENCRYPT = 8; + private static final String[] RAWCONTACT_PROJECTION = { + ContactsContract.RawContacts.CONTACT_ID + }; + + private static final int INDEX_CONTACT_ID = 0; + private void loadData(Uri dataUri) { mDataUri = dataUri; @@ -241,6 +246,33 @@ public class ViewKeyFragment extends LoaderFragment implements case LOADER_ID_USER_IDS: return UserIdsAdapter.createLoader(getActivity(), mDataUri); + //we need a separate loader for linked contact to ensure refreshing on verification + case LOADER_ID_LINKED_CONTACT: { + //passed in args to explicitly specify their need + long masterKeyId = args.getLong(LOADER_LINKED_CONTACT_MASTER_KEY_ID); + boolean isSecret = args.getBoolean(LOADER_LINKED_CONTACT_IS_SECRET); + + Uri baseUri; + if (isSecret) + baseUri = ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI; + else + baseUri = ContactsContract.RawContacts.CONTENT_URI; + + return new CursorLoader( + getActivity(), + baseUri, + RAWCONTACT_PROJECTION, + ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + + ContactsContract.RawContacts.SOURCE_ID + "=? AND " + + ContactsContract.RawContacts.DELETED + "=?", + new String[]{//"0" for "not deleted" + Constants.ACCOUNT_TYPE, + Long.toString(masterKeyId), + "0" + }, + null); + } + default: return null; } @@ -263,16 +295,26 @@ public class ViewKeyFragment extends LoaderFragment implements mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; - //TODO system to allow immediate refreshing of system contact on verification - if (!mSystemContactLoaded) {//ensure we load linked system contact only once - long masterKeyId = data.getLong(INDEX_MASTER_KEY_ID); - loadLinkedSystemContact(masterKeyId); - } // load user ids after we know if it's a secret key mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, !mIsSecret, null); mUserIds.setAdapter(mUserIdsAdapter); getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); + long masterKeyId = data.getLong(INDEX_MASTER_KEY_ID); + // we need to load linked contact here to prevent lag introduced by loader + // for the linked contact + long contactId = ContactHelper.findContactId( + getActivity().getContentResolver(), + masterKeyId); + loadLinkedSystemContact(contactId); + + Bundle linkedContactData = new Bundle(); + linkedContactData.putLong(LOADER_LINKED_CONTACT_MASTER_KEY_ID, masterKeyId); + linkedContactData.putBoolean(LOADER_LINKED_CONTACT_IS_SECRET, mIsSecret); + + // initialises loader for contact query so we can listen to any updates + getLoaderManager().initLoader(LOADER_ID_LINKED_CONTACT, linkedContactData, this); + break; } } @@ -282,6 +324,14 @@ public class ViewKeyFragment extends LoaderFragment implements break; } + case LOADER_ID_LINKED_CONTACT: { + if (data.moveToFirst()) {// if we have a linked contact + long contactId = data.getLong(INDEX_CONTACT_ID); + loadLinkedSystemContact(contactId); + } + break; + } + } setContentShown(true); } -- cgit v1.2.3 From 083cd100cebbbfdca3a0df76e050b817d8711cd8 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Wed, 8 Apr 2015 00:58:21 +0530 Subject: hide linked system contact card if no contact present --- .../keychain/ui/ViewKeyFragment.java | 32 ++++++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java index ce353f82e..1e02ca450 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java @@ -29,6 +29,7 @@ import android.provider.ContactsContract; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; +import android.support.v7.widget.CardView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -37,7 +38,6 @@ import android.widget.*; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; @@ -56,6 +56,7 @@ public class ViewKeyFragment extends LoaderFragment implements boolean mIsSecret = false; + CardView mSystemContactCard; LinearLayout mSystemContactLayout; ImageView mSystemContactPicture; TextView mSystemContactName; @@ -64,9 +65,9 @@ public class ViewKeyFragment extends LoaderFragment implements private static final int LOADER_ID_USER_IDS = 1; private static final int LOADER_ID_LINKED_CONTACT = 2; - private static final String LOADER_LINKED_CONTACT_MASTER_KEY_ID + private static final String LOADER_EXTRA_LINKED_CONTACT_MASTER_KEY_ID = "loader_linked_contact_master_key_id"; - private static final String LOADER_LINKED_CONTACT_IS_SECRET + private static final String LOADER_EXTRA_LINKED_CONTACT_IS_SECRET = "loader_linked_contact_is_secret"; private UserIdsAdapter mUserIdsAdapter; @@ -100,6 +101,7 @@ public class ViewKeyFragment extends LoaderFragment implements } }); + mSystemContactCard = (CardView) view.findViewById(R.id.linked_system_contact_card); mSystemContactLayout = (LinearLayout) view.findViewById(R.id.system_contact_layout); mSystemContactName = (TextView) view.findViewById(R.id.system_contact_name); mSystemContactPicture = (ImageView) view.findViewById(R.id.system_contact_picture); @@ -124,9 +126,9 @@ public class ViewKeyFragment extends LoaderFragment implements } /** - * Expects to be called only if a linked system contact exists. Sets name, picture + * Hides card if no linked system contact exists. Sets name, picture * and onClickListener for the linked system contact's layout. - * In the case of a secret key, "me" contact details are loaded. + * In the case of a secret key, "me" (own profile) contact details are loaded. * * @param contactId */ @@ -147,6 +149,8 @@ public class ViewKeyFragment extends LoaderFragment implements } if (contactName != null) {//contact name exists for given master key + showLinkedSystemContact(); + mSystemContactName.setText(contactName); Bitmap picture; @@ -163,9 +167,19 @@ public class ViewKeyFragment extends LoaderFragment implements launchContactActivity(contactId, context); } }); + } else { + hideLinkedSystemContact(); } } + private void hideLinkedSystemContact() { + mSystemContactCard.setVisibility(View.GONE); + } + + private void showLinkedSystemContact() { + mSystemContactCard.setVisibility(View.VISIBLE); + } + /** * launches the default android Contacts app to view a contact with the passed * contactId (CONTACT_ID column from ContactsContract.RawContact table which is _ID column in @@ -249,8 +263,8 @@ public class ViewKeyFragment extends LoaderFragment implements //we need a separate loader for linked contact to ensure refreshing on verification case LOADER_ID_LINKED_CONTACT: { //passed in args to explicitly specify their need - long masterKeyId = args.getLong(LOADER_LINKED_CONTACT_MASTER_KEY_ID); - boolean isSecret = args.getBoolean(LOADER_LINKED_CONTACT_IS_SECRET); + long masterKeyId = args.getLong(LOADER_EXTRA_LINKED_CONTACT_MASTER_KEY_ID); + boolean isSecret = args.getBoolean(LOADER_EXTRA_LINKED_CONTACT_IS_SECRET); Uri baseUri; if (isSecret) @@ -309,8 +323,8 @@ public class ViewKeyFragment extends LoaderFragment implements loadLinkedSystemContact(contactId); Bundle linkedContactData = new Bundle(); - linkedContactData.putLong(LOADER_LINKED_CONTACT_MASTER_KEY_ID, masterKeyId); - linkedContactData.putBoolean(LOADER_LINKED_CONTACT_IS_SECRET, mIsSecret); + linkedContactData.putLong(LOADER_EXTRA_LINKED_CONTACT_MASTER_KEY_ID, masterKeyId); + linkedContactData.putBoolean(LOADER_EXTRA_LINKED_CONTACT_IS_SECRET, mIsSecret); // initialises loader for contact query so we can listen to any updates getLoaderManager().initLoader(LOADER_ID_LINKED_CONTACT, linkedContactData, this); -- cgit v1.2.3 From 7074b443472b620dbfd452d1682b30407b1851b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 10 Apr 2015 15:58:37 +0200 Subject: Cache CryptoInputParcel in OpenPgpService --- .../sufficientlysecure/keychain/ui/NfcOperationActivity.java | 11 ++++++----- .../keychain/ui/PassphraseDialogActivity.java | 7 ++++--- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index d70b0aad1..02fc81825 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -16,6 +16,7 @@ import android.view.WindowManager; import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.remote.OpenPgpService; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -69,7 +70,7 @@ public class NfcOperationActivity extends BaseNfcActivity { @Override protected void onNfcPerform() throws IOException { - CryptoInputParcel resultData = new CryptoInputParcel(mRequiredInput.mSignatureTime); + CryptoInputParcel inputParcel = new CryptoInputParcel(mRequiredInput.mSignatureTime); switch (mRequiredInput.mType) { @@ -77,7 +78,7 @@ public class NfcOperationActivity extends BaseNfcActivity { for (int i = 0; i < mRequiredInput.mInputHashes.length; i++) { byte[] hash = mRequiredInput.mInputHashes[i]; byte[] decryptedSessionKey = nfcDecryptSessionKey(hash); - resultData.addCryptoData(hash, decryptedSessionKey); + inputParcel.addCryptoData(hash, decryptedSessionKey); } break; @@ -86,17 +87,17 @@ public class NfcOperationActivity extends BaseNfcActivity { byte[] hash = mRequiredInput.mInputHashes[i]; int algo = mRequiredInput.mSignAlgos[i]; byte[] signedHash = nfcCalculateSignature(hash, algo); - resultData.addCryptoData(hash, signedHash); + inputParcel.addCryptoData(hash, signedHash); } break; } if (mServiceIntent != null) { - mServiceIntent.putExtra(OpenPgpApi.EXTRA_CRYPTO_INPUT, resultData); + OpenPgpService.cacheCryptoInputParcel(mServiceIntent, inputParcel); setResult(RESULT_OK, mServiceIntent); } else { Intent result = new Intent(); - result.putExtra(NfcOperationActivity.RESULT_DATA, resultData); + result.putExtra(NfcOperationActivity.RESULT_DATA, inputParcel); setResult(RESULT_OK, result); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index 007608f80..bf6129407 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -53,6 +53,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.remote.OpenPgpService; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -425,14 +426,14 @@ public class PassphraseDialogActivity extends FragmentActivity { return; } + CryptoInputParcel inputParcel = new CryptoInputParcel(null, passphrase); if (mServiceIntent != null) { - // TODO really pass this through the PendingIntent? - mServiceIntent.putExtra(OpenPgpApi.EXTRA_CRYPTO_INPUT, new CryptoInputParcel(null, passphrase)); + OpenPgpService.cacheCryptoInputParcel(mServiceIntent, inputParcel); getActivity().setResult(RESULT_OK, mServiceIntent); } else { // also return passphrase back to activity Intent returnIntent = new Intent(); - returnIntent.putExtra(RESULT_CRYPTO_INPUT, new CryptoInputParcel(null, passphrase)); + returnIntent.putExtra(RESULT_CRYPTO_INPUT, inputParcel); getActivity().setResult(RESULT_OK, returnIntent); } -- cgit v1.2.3 From 256d644d03f989132e9db01e15f75aaee2f76157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 13 Apr 2015 23:29:35 +0200 Subject: IMplement CryptoInputParcelCacheService --- .../org/sufficientlysecure/keychain/ui/NfcOperationActivity.java | 6 ++---- .../sufficientlysecure/keychain/ui/PassphraseDialogActivity.java | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index 02fc81825..a0b38c2b2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -10,13 +10,11 @@ import android.annotation.TargetApi; import android.content.Intent; import android.os.Build; import android.os.Bundle; -import android.os.Parcelable; import android.view.WindowManager; -import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.remote.OpenPgpService; +import org.sufficientlysecure.keychain.remote.CryptoInputParcelCacheService; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; @@ -93,7 +91,7 @@ public class NfcOperationActivity extends BaseNfcActivity { } if (mServiceIntent != null) { - OpenPgpService.cacheCryptoInputParcel(mServiceIntent, inputParcel); + CryptoInputParcelCacheService.addCryptoInputParcel(this, mServiceIntent, inputParcel); setResult(RESULT_OK, mServiceIntent); } else { Intent result = new Intent(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index bf6129407..84612002f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -41,7 +41,6 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; -import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; @@ -53,11 +52,10 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.remote.OpenPgpService; +import org.sufficientlysecure.keychain.remote.CryptoInputParcelCacheService; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; -import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; @@ -428,7 +426,7 @@ public class PassphraseDialogActivity extends FragmentActivity { CryptoInputParcel inputParcel = new CryptoInputParcel(null, passphrase); if (mServiceIntent != null) { - OpenPgpService.cacheCryptoInputParcel(mServiceIntent, inputParcel); + CryptoInputParcelCacheService.addCryptoInputParcel(getActivity(), mServiceIntent, inputParcel); getActivity().setResult(RESULT_OK, mServiceIntent); } else { // also return passphrase back to activity -- cgit v1.2.3 From f981c36bf4124f892c5b4c75f89437f320772fbd Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 14 Apr 2015 15:34:25 -0400 Subject: Move PIN verify inside sign/decrypt operation and set correct mode. --- .../keychain/ui/base/BaseNfcActivity.java | 64 +++++++++++++++------- 1 file changed, 45 insertions(+), 19 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index 9b10ccdb1..1faa5f6b5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -185,25 +185,6 @@ public abstract class BaseNfcActivity extends BaseActivity { throw new IOException("Initialization failed!"); } - if (mPin != null) { - - byte[] pin = new String(mPin.getCharArray()).getBytes(); - - // Command APDU for VERIFY command (page 32) - String login = - "00" // CLA - + "20" // INS - + "00" // P1 - + "82" // P2 (PW1) - + String.format("%02x", pin.length) // Lc - + Hex.toHexString(pin); - if (!nfcCommunicate(login).equals(accepted)) { // login - handlePinError(); - return; - } - - } - onNfcPerform(); mIsoDep.close(); @@ -321,6 +302,28 @@ public abstract class BaseNfcActivity extends BaseActivity { */ public byte[] nfcCalculateSignature(byte[] hash, int hashAlgo) throws IOException { + if (mPin != null) { + + byte[] pin = new String(mPin.getCharArray()).getBytes(); + // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. + // See specification, page 51 + String accepted = "9000"; + + // Command APDU for VERIFY command (page 32) + String login = + "00" // CLA + + "20" // INS + + "00" // P1 + + "81" // P2 (PW1 with mode 81 for signing) + + String.format("%02x", pin.length) // Lc + + Hex.toHexString(pin); + if (!nfcCommunicate(login).equals(accepted)) { // login + handlePinError(); + throw new IOException("Bad PIN!"); + } + + } + // dsi, including Lc String dsi; @@ -413,6 +416,29 @@ public abstract class BaseNfcActivity extends BaseActivity { * @return the decoded session key */ public byte[] nfcDecryptSessionKey(byte[] encryptedSessionKey) throws IOException { + + if (mPin != null) { + + byte[] pin = new String(mPin.getCharArray()).getBytes(); + // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. + // See specification, page 51 + String accepted = "9000"; + + // Command APDU for VERIFY command (page 32) + String login = + "00" // CLA + + "20" // INS + + "00" // P1 + + "82" // P2 (PW1 with mode 82 for decryption) + + String.format("%02x", pin.length) // Lc + + Hex.toHexString(pin); + if (!nfcCommunicate(login).equals(accepted)) { // login + handlePinError(); + throw new IOException("Bad PIN!"); + } + + } + String firstApdu = "102a8086fe"; String secondApdu = "002a808603"; String le = "00"; -- cgit v1.2.3 From f85befd98284663bf58cf9eb42238e2f0f4b2459 Mon Sep 17 00:00:00 2001 From: Joey Castillo Date: Tue, 14 Apr 2015 16:19:28 -0400 Subject: Consolidate PIN verify operation in nfcVerifyPIN method. --- .../keychain/ui/base/BaseNfcActivity.java | 72 +++++++++------------- 1 file changed, 28 insertions(+), 44 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index 1faa5f6b5..b36b9b89e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -301,28 +301,7 @@ public abstract class BaseNfcActivity extends BaseActivity { * @return a big integer representing the MPI for the given hash */ public byte[] nfcCalculateSignature(byte[] hash, int hashAlgo) throws IOException { - - if (mPin != null) { - - byte[] pin = new String(mPin.getCharArray()).getBytes(); - // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. - // See specification, page 51 - String accepted = "9000"; - - // Command APDU for VERIFY command (page 32) - String login = - "00" // CLA - + "20" // INS - + "00" // P1 - + "81" // P2 (PW1 with mode 81 for signing) - + String.format("%02x", pin.length) // Lc - + Hex.toHexString(pin); - if (!nfcCommunicate(login).equals(accepted)) { // login - handlePinError(); - throw new IOException("Bad PIN!"); - } - - } + nfcVerifyPIN(0x81); // (Verify PW1 with mode 81 for signing) // dsi, including Lc String dsi; @@ -416,28 +395,7 @@ public abstract class BaseNfcActivity extends BaseActivity { * @return the decoded session key */ public byte[] nfcDecryptSessionKey(byte[] encryptedSessionKey) throws IOException { - - if (mPin != null) { - - byte[] pin = new String(mPin.getCharArray()).getBytes(); - // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. - // See specification, page 51 - String accepted = "9000"; - - // Command APDU for VERIFY command (page 32) - String login = - "00" // CLA - + "20" // INS - + "00" // P1 - + "82" // P2 (PW1 with mode 82 for decryption) - + String.format("%02x", pin.length) // Lc - + Hex.toHexString(pin); - if (!nfcCommunicate(login).equals(accepted)) { // login - handlePinError(); - throw new IOException("Bad PIN!"); - } - - } + nfcVerifyPIN(0x82); // (Verify PW1 with mode 82 for decryption) String firstApdu = "102a8086fe"; String secondApdu = "002a808603"; @@ -462,6 +420,32 @@ public abstract class BaseNfcActivity extends BaseActivity { return Hex.decode(decryptedSessionKey); } + /** Verifies the user's PW1 with the appropriate mode. + * + * @param mode This is 0x81 for signing, 0x82 for everything else + */ + public void nfcVerifyPIN(int mode) throws IOException { + if (mPin != null) { + byte[] pin = new String(mPin.getCharArray()).getBytes(); + // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. + // See specification, page 51 + String accepted = "9000"; + + // Command APDU for VERIFY command (page 32) + String login = + "00" // CLA + + "20" // INS + + "00" // P1 + + String.format("%02x", mode) // P2 + + String.format("%02x", pin.length) // Lc + + Hex.toHexString(pin); + if (!nfcCommunicate(login).equals(accepted)) { // login + handlePinError(); + throw new IOException("Bad PIN!"); + } + } + } + /** * Prints a message to the screen * -- cgit v1.2.3 From 84deba98867607e139f761cd34665fb44f14069f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 15 Apr 2015 09:50:34 +0200 Subject: Reformat nfcVerifyPIN --- .../sufficientlysecure/keychain/ui/base/BaseNfcActivity.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index b36b9b89e..ff5268c7c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -433,12 +433,12 @@ public abstract class BaseNfcActivity extends BaseActivity { // Command APDU for VERIFY command (page 32) String login = - "00" // CLA - + "20" // INS - + "00" // P1 - + String.format("%02x", mode) // P2 - + String.format("%02x", pin.length) // Lc - + Hex.toHexString(pin); + "00" // CLA + + "20" // INS + + "00" // P1 + + String.format("%02x", mode) // P2 + + String.format("%02x", pin.length) // Lc + + Hex.toHexString(pin); if (!nfcCommunicate(login).equals(accepted)) { // login handlePinError(); throw new IOException("Bad PIN!"); -- cgit v1.2.3 From f41758261ffa51274267110d5b0d4dc1de44837e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 15 Apr 2015 09:55:29 +0200 Subject: Clean up NfcOperationActivity --- .../keychain/ui/NfcOperationActivity.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index a0b38c2b2..25cc13fcb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -27,10 +27,9 @@ import java.io.IOException; /** * This class provides a communication interface to OpenPGP applications on ISO SmartCard compliant * NFC devices. - * + *

* For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf */ -@TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) public class NfcOperationActivity extends BaseNfcActivity { public static final String EXTRA_REQUIRED_INPUT = "required_input"; @@ -71,16 +70,15 @@ public class NfcOperationActivity extends BaseNfcActivity { CryptoInputParcel inputParcel = new CryptoInputParcel(mRequiredInput.mSignatureTime); switch (mRequiredInput.mType) { - - case NFC_DECRYPT: + case NFC_DECRYPT: { for (int i = 0; i < mRequiredInput.mInputHashes.length; i++) { byte[] hash = mRequiredInput.mInputHashes[i]; byte[] decryptedSessionKey = nfcDecryptSessionKey(hash); inputParcel.addCryptoData(hash, decryptedSessionKey); } break; - - case NFC_SIGN: + } + case NFC_SIGN: { for (int i = 0; i < mRequiredInput.mInputHashes.length; i++) { byte[] hash = mRequiredInput.mInputHashes[i]; int algo = mRequiredInput.mSignAlgos[i]; @@ -88,6 +86,7 @@ public class NfcOperationActivity extends BaseNfcActivity { inputParcel.addCryptoData(hash, signedHash); } break; + } } if (mServiceIntent != null) { @@ -100,7 +99,6 @@ public class NfcOperationActivity extends BaseNfcActivity { } finish(); - } @Override @@ -120,6 +118,6 @@ public class NfcOperationActivity extends BaseNfcActivity { this, mRequiredInput.getMasterKeyId(), mRequiredInput.getSubKeyId()); obtainYubikeyPin(RequiredInputParcel.createRequiredPassphrase(mRequiredInput)); - } + } -- cgit v1.2.3 From 3668c8897d88989780da800ecd648c7b33a0e8f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 15 Apr 2015 10:02:41 +0200 Subject: Fix YubiKey naming, cleanup --- .../keychain/ui/DecryptFragment.java | 19 -- .../keychain/ui/NfcOperationActivity.java | 8 +- .../keychain/ui/PassphraseDialogActivity.java | 2 +- .../keychain/ui/SettingsActivity.java | 28 +-- .../keychain/ui/ViewKeyActivity.java | 8 +- .../keychain/ui/ViewKeyYubiKeyFragment.java | 218 ++++++++++++++++++++ .../keychain/ui/ViewKeyYubikeyFragment.java | 220 --------------------- .../keychain/ui/base/BaseNfcActivity.java | 25 ++- 8 files changed, 260 insertions(+), 268 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index f320a6d84..68b758bab 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -85,25 +85,6 @@ public abstract class DecryptFragment extends CryptoOperationFragment { startActivity(viewKeyIntent); } -// protected void startPassphraseDialog(long subkeyId) { -// Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); -// intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId); -// startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); -// } -// -// protected void startNfcDecrypt(long subKeyId, Passphrase pin, byte[] encryptedSessionKey) { -// // build PendingIntent for Yubikey NFC operations -// Intent intent = new Intent(getActivity(), NfcActivity.class); -// intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY); -// intent.putExtra(NfcActivity.EXTRA_SERVICE_INTENT, new Intent()); // not used, only relevant to OpenPgpService -// intent.putExtra(NfcActivity.EXTRA_KEY_ID, subKeyId); -// intent.putExtra(NfcActivity.EXTRA_PIN, pin); -// -// intent.putExtra(NfcActivity.EXTRA_NFC_ENC_SESSION_KEY, encryptedSessionKey); -// -// startActivityForResult(intent, REQUEST_CODE_NFC_DECRYPT); -// } - /** * * @return returns false if signature is invalid, key is revoked or expired. diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java index 25cc13fcb..aa66053fa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java @@ -6,9 +6,7 @@ package org.sufficientlysecure.keychain.ui; -import android.annotation.TargetApi; import android.content.Intent; -import android.os.Build; import android.os.Bundle; import android.view.WindowManager; @@ -56,7 +54,7 @@ public class NfcOperationActivity extends BaseNfcActivity { mServiceIntent = data.getParcelable(EXTRA_SERVICE_INTENT); // obtain passphrase for this subkey - obtainYubikeyPin(RequiredInputParcel.createRequiredPassphrase(mRequiredInput)); + obtainYubiKeyPin(RequiredInputParcel.createRequiredPassphrase(mRequiredInput)); } @Override @@ -106,7 +104,7 @@ public class NfcOperationActivity extends BaseNfcActivity { // avoid a loop Preferences prefs = Preferences.getPreferences(this); - if (prefs.useDefaultYubikeyPin()) { + if (prefs.useDefaultYubiKeyPin()) { toast(getString(R.string.error_pin_nodefault)); setResult(RESULT_CANCELED); finish(); @@ -117,7 +115,7 @@ public class NfcOperationActivity extends BaseNfcActivity { PassphraseCacheService.clearCachedPassphrase( this, mRequiredInput.getMasterKeyId(), mRequiredInput.getSubKeyId()); - obtainYubikeyPin(RequiredInputParcel.createRequiredPassphrase(mRequiredInput)); + obtainYubiKeyPin(RequiredInputParcel.createRequiredPassphrase(mRequiredInput)); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index 84612002f..4e926c0fe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -314,7 +314,7 @@ public class PassphraseDialogActivity extends FragmentActivity { mPassphraseEditText.setImeActionLabel(getString(android.R.string.ok), EditorInfo.IME_ACTION_DONE); mPassphraseEditText.setOnEditorActionListener(this); - if (keyType == CanonicalizedSecretKey.SecretKeyType.DIVERT_TO_CARD && Preferences.getPreferences(activity).useNumKeypadForYubikeyPin()) { + if (keyType == CanonicalizedSecretKey.SecretKeyType.DIVERT_TO_CARD && Preferences.getPreferences(activity).useNumKeypadForYubiKeyPin()) { mPassphraseEditText.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_TEXT_VARIATION_PASSWORD); } else if (keyType == CanonicalizedSecretKey.SecretKeyType.PIN) { mPassphraseEditText.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_TEXT_VARIATION_PASSWORD); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java index 210960b65..442bdf8f7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java @@ -107,10 +107,10 @@ public class SettingsActivity extends PreferenceActivity { values[i] = "" + valueIds[i]; } - initializeUseDefaultYubikeyPin( + initializeUseDefaultYubiKeyPin( (CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN)); - initializeUseNumKeypadForYubikeyPin( + initializeUseNumKeypadForYubiKeyPin( (CheckBoxPreference) findPreference(Constants.Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN)); } @@ -262,10 +262,10 @@ public class SettingsActivity extends PreferenceActivity { values[i] = "" + valueIds[i]; } - initializeUseDefaultYubikeyPin( + initializeUseDefaultYubiKeyPin( (CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN)); - initializeUseNumKeypadForYubikeyPin( + initializeUseNumKeypadForYubiKeyPin( (CheckBoxPreference) findPreference(Constants.Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN)); } } @@ -335,23 +335,23 @@ public class SettingsActivity extends PreferenceActivity { return serverSummary + "; " + context.getString(R.string.label_preferred) + ": " + sPreferences.getPreferredKeyserver(); } - private static void initializeUseDefaultYubikeyPin(final CheckBoxPreference mUseDefaultYubikeyPin) { - mUseDefaultYubikeyPin.setChecked(sPreferences.useDefaultYubikeyPin()); - mUseDefaultYubikeyPin.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + private static void initializeUseDefaultYubiKeyPin(final CheckBoxPreference mUseDefaultYubiKeyPin) { + mUseDefaultYubiKeyPin.setChecked(sPreferences.useDefaultYubiKeyPin()); + mUseDefaultYubiKeyPin.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { - mUseDefaultYubikeyPin.setChecked((Boolean) newValue); - sPreferences.setUseDefaultYubikeyPin((Boolean) newValue); + mUseDefaultYubiKeyPin.setChecked((Boolean) newValue); + sPreferences.setUseDefaultYubiKeyPin((Boolean) newValue); return false; } }); } - private static void initializeUseNumKeypadForYubikeyPin(final CheckBoxPreference mUseNumKeypadForYubikeyPin) { - mUseNumKeypadForYubikeyPin.setChecked(sPreferences.useNumKeypadForYubikeyPin()); - mUseNumKeypadForYubikeyPin.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + private static void initializeUseNumKeypadForYubiKeyPin(final CheckBoxPreference mUseNumKeypadForYubiKeyPin) { + mUseNumKeypadForYubiKeyPin.setChecked(sPreferences.useNumKeypadForYubiKeyPin()); + mUseNumKeypadForYubiKeyPin.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { - mUseNumKeypadForYubikeyPin.setChecked((Boolean) newValue); - sPreferences.setUseNumKeypadForYubikeyPin((Boolean) newValue); + mUseNumKeypadForYubiKeyPin.setChecked((Boolean) newValue); + sPreferences.setUseNumKeypadForYubiKeyPin((Boolean) newValue); return false; } }); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index b063df2fb..5466c0b9a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -281,7 +281,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements byte[] nfcFingerprints = intent.getByteArrayExtra(EXTRA_NFC_FINGERPRINTS); String nfcUserId = intent.getStringExtra(EXTRA_NFC_USER_ID); byte[] nfcAid = intent.getByteArrayExtra(EXTRA_NFC_AID); - showYubikeyFragment(nfcFingerprints, nfcUserId, nfcAid); + showYubiKeyFragment(nfcFingerprints, nfcUserId, nfcAid); } } @@ -593,12 +593,12 @@ public class ViewKeyActivity extends BaseNfcActivity implements } } - showYubikeyFragment(nfcFingerprints, nfcUserId, nfcAid); + showYubiKeyFragment(nfcFingerprints, nfcUserId, nfcAid); } - public void showYubikeyFragment(byte[] nfcFingerprints, String nfcUserId, byte[] nfcAid) { - ViewKeyYubikeyFragment frag = ViewKeyYubikeyFragment.newInstance( + public void showYubiKeyFragment(byte[] nfcFingerprints, String nfcUserId, byte[] nfcAid) { + ViewKeyYubiKeyFragment frag = ViewKeyYubiKeyFragment.newInstance( nfcFingerprints, nfcUserId, nfcAid); FragmentManager manager = getSupportFragmentManager(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java new file mode 100644 index 000000000..a2c158e7d --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java @@ -0,0 +1,218 @@ +package org.sufficientlysecure.keychain.ui; + + +import java.nio.ByteBuffer; +import java.util.Arrays; + +import android.content.Intent; +import android.database.Cursor; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import org.spongycastle.util.encoders.Hex; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; +import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; +import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.ServiceProgressHandler; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; + + +public class ViewKeyYubiKeyFragment extends Fragment + implements LoaderCallbacks { + + public static final String ARG_FINGERPRINT = "fingerprint"; + public static final String ARG_USER_ID = "user_id"; + public static final String ARG_CARD_AID = "aid"; + private byte[][] mFingerprints; + private String mUserId; + private byte[] mCardAid; + private long mMasterKeyId; + private Button vButton; + private TextView vStatus; + + public static ViewKeyYubiKeyFragment newInstance(byte[] fingerprints, String userId, byte[] aid) { + + ViewKeyYubiKeyFragment frag = new ViewKeyYubiKeyFragment(); + + Bundle args = new Bundle(); + args.putByteArray(ARG_FINGERPRINT, fingerprints); + args.putString(ARG_USER_ID, userId); + args.putByteArray(ARG_CARD_AID, aid); + frag.setArguments(args); + + return frag; + + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle args = getArguments(); + ByteBuffer buf = ByteBuffer.wrap(args.getByteArray(ARG_FINGERPRINT)); + mFingerprints = new byte[buf.remaining()/40][]; + for (int i = 0; i < mFingerprints.length; i++) { + mFingerprints[i] = new byte[20]; + buf.get(mFingerprints[i]); + } + mUserId = args.getString(ARG_USER_ID); + mCardAid = args.getByteArray(ARG_CARD_AID); + + mMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mFingerprints[0]); + + getLoaderManager().initLoader(0, null, this); + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.view_key_yubikey, null); + + TextView vSerNo = (TextView) view.findViewById(R.id.yubikey_serno); + TextView vUserId = (TextView) view.findViewById(R.id.yubikey_userid); + + String serno = Hex.toHexString(mCardAid, 10, 4); + vSerNo.setText(getString(R.string.yubikey_serno, serno)); + + if (!mUserId.isEmpty()) { + vUserId.setText(getString(R.string.yubikey_key_holder, mUserId)); + } else { + vUserId.setText(getString(R.string.yubikey_key_holder_unset)); + } + + vButton = (Button) view.findViewById(R.id.button_bind); + vButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + promoteToSecretKey(); + } + }); + + vStatus = (TextView) view.findViewById(R.id.yubikey_status); + + return view; + } + + public void promoteToSecretKey() { + + ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == MessageStatus.OKAY.ordinal()) { + // get returned data bundle + Bundle returnData = message.getData(); + + PromoteKeyResult result = + returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); + + result.createNotify(getActivity()).show(); + } + + } + }; + + // Send all information needed to service to decrypt in other thread + Intent intent = new Intent(getActivity(), KeychainIntentService.class); + + // fill values for this action + + intent.setAction(KeychainIntentService.ACTION_PROMOTE_KEYRING); + + Bundle data = new Bundle(); + data.putLong(KeychainIntentService.PROMOTE_MASTER_KEY_ID, mMasterKeyId); + data.putByteArray(KeychainIntentService.PROMOTE_CARD_AID, mCardAid); + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(saveHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // start service with intent + getActivity().startService(intent); + + } + + public static final String[] PROJECTION = new String[]{ + Keys._ID, + Keys.KEY_ID, + Keys.RANK, + Keys.HAS_SECRET, + Keys.FINGERPRINT + }; + private static final int INDEX_KEY_ID = 1; + private static final int INDEX_RANK = 2; + private static final int INDEX_HAS_SECRET = 3; + private static final int INDEX_FINGERPRINT = 4; + + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new CursorLoader(getActivity(), Keys.buildKeysUri(mMasterKeyId), + PROJECTION, null, null, null); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + if (!data.moveToFirst()) { + // wut? + return; + } + + boolean allBound = true; + boolean noneBound = true; + + do { + SecretKeyType keyType = SecretKeyType.fromNum(data.getInt(INDEX_HAS_SECRET)); + byte[] fingerprint = data.getBlob(INDEX_FINGERPRINT); + Integer index = naiveIndexOf(mFingerprints, fingerprint); + if (index == null) { + continue; + } + if (keyType == SecretKeyType.DIVERT_TO_CARD) { + noneBound = false; + } else { + allBound = false; + } + } while (data.moveToNext()); + + if (allBound) { + vButton.setVisibility(View.GONE); + vStatus.setText(R.string.yubikey_status_bound); + } else { + vButton.setVisibility(View.VISIBLE); + vStatus.setText(noneBound + ? R.string.yubikey_status_unbound + : R.string.yubikey_status_partly); + } + + } + + public Integer naiveIndexOf(byte[][] haystack, byte[] needle) { + for (int i = 0; i < haystack.length; i++) { + if (Arrays.equals(needle, haystack[i])) { + return i; + } + } + return null; + } + + @Override + public void onLoaderReset(Loader loader) { + + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java deleted file mode 100644 index 1482b70a7..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubikeyFragment.java +++ /dev/null @@ -1,220 +0,0 @@ -package org.sufficientlysecure.keychain.ui; - - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import android.app.ProgressDialog; -import android.content.Intent; -import android.database.Cursor; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.support.v4.app.Fragment; -import android.support.v4.app.LoaderManager.LoaderCallbacks; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; - -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; -import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; -import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.ServiceProgressHandler; -import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; - - -public class ViewKeyYubikeyFragment extends Fragment - implements LoaderCallbacks { - - public static final String ARG_FINGERPRINT = "fingerprint"; - public static final String ARG_USER_ID = "user_id"; - public static final String ARG_CARD_AID = "aid"; - private byte[][] mFingerprints; - private String mUserId; - private byte[] mCardAid; - private long mMasterKeyId; - private Button vButton; - private TextView vStatus; - - public static ViewKeyYubikeyFragment newInstance(byte[] fingerprints, String userId, byte[] aid) { - - ViewKeyYubikeyFragment frag = new ViewKeyYubikeyFragment(); - - Bundle args = new Bundle(); - args.putByteArray(ARG_FINGERPRINT, fingerprints); - args.putString(ARG_USER_ID, userId); - args.putByteArray(ARG_CARD_AID, aid); - frag.setArguments(args); - - return frag; - - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Bundle args = getArguments(); - ByteBuffer buf = ByteBuffer.wrap(args.getByteArray(ARG_FINGERPRINT)); - mFingerprints = new byte[buf.remaining()/40][]; - for (int i = 0; i < mFingerprints.length; i++) { - mFingerprints[i] = new byte[20]; - buf.get(mFingerprints[i]); - } - mUserId = args.getString(ARG_USER_ID); - mCardAid = args.getByteArray(ARG_CARD_AID); - - mMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mFingerprints[0]); - - getLoaderManager().initLoader(0, null, this); - - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.view_key_yubikey, null); - - TextView vSerNo = (TextView) view.findViewById(R.id.yubikey_serno); - TextView vUserId = (TextView) view.findViewById(R.id.yubikey_userid); - - String serno = Hex.toHexString(mCardAid, 10, 4); - vSerNo.setText(getString(R.string.yubikey_serno, serno)); - - if (!mUserId.isEmpty()) { - vUserId.setText(getString(R.string.yubikey_key_holder, mUserId)); - } else { - vUserId.setText(getString(R.string.yubikey_key_holder_unset)); - } - - vButton = (Button) view.findViewById(R.id.button_bind); - vButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - promoteToSecretKey(); - } - }); - - vStatus = (TextView) view.findViewById(R.id.yubikey_status); - - return view; - } - - public void promoteToSecretKey() { - - ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == MessageStatus.OKAY.ordinal()) { - // get returned data bundle - Bundle returnData = message.getData(); - - PromoteKeyResult result = - returnData.getParcelable(DecryptVerifyResult.EXTRA_RESULT); - - result.createNotify(getActivity()).show(); - } - - } - }; - - // Send all information needed to service to decrypt in other thread - Intent intent = new Intent(getActivity(), KeychainIntentService.class); - - // fill values for this action - - intent.setAction(KeychainIntentService.ACTION_PROMOTE_KEYRING); - - Bundle data = new Bundle(); - data.putLong(KeychainIntentService.PROMOTE_MASTER_KEY_ID, mMasterKeyId); - data.putByteArray(KeychainIntentService.PROMOTE_CARD_AID, mCardAid); - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // start service with intent - getActivity().startService(intent); - - } - - public static final String[] PROJECTION = new String[]{ - Keys._ID, - Keys.KEY_ID, - Keys.RANK, - Keys.HAS_SECRET, - Keys.FINGERPRINT - }; - private static final int INDEX_KEY_ID = 1; - private static final int INDEX_RANK = 2; - private static final int INDEX_HAS_SECRET = 3; - private static final int INDEX_FINGERPRINT = 4; - - @Override - public Loader onCreateLoader(int id, Bundle args) { - return new CursorLoader(getActivity(), Keys.buildKeysUri(mMasterKeyId), - PROJECTION, null, null, null); - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - if (!data.moveToFirst()) { - // wut? - return; - } - - boolean allBound = true; - boolean noneBound = true; - - do { - SecretKeyType keyType = SecretKeyType.fromNum(data.getInt(INDEX_HAS_SECRET)); - byte[] fingerprint = data.getBlob(INDEX_FINGERPRINT); - Integer index = naiveIndexOf(mFingerprints, fingerprint); - if (index == null) { - continue; - } - if (keyType == SecretKeyType.DIVERT_TO_CARD) { - noneBound = false; - } else { - allBound = false; - } - } while (data.moveToNext()); - - if (allBound) { - vButton.setVisibility(View.GONE); - vStatus.setText(R.string.yubikey_status_bound); - } else { - vButton.setVisibility(View.VISIBLE); - vStatus.setText(noneBound - ? R.string.yubikey_status_unbound - : R.string.yubikey_status_partly); - } - - } - - public Integer naiveIndexOf(byte[][] haystack, byte[] needle) { - for (int i = 0; i < haystack.length; i++) { - if (Arrays.equals(needle, haystack[i])) { - return i; - } - } - return null; - } - - @Override - public void onLoaderReset(Loader loader) { - - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index ff5268c7c..f55c8b17a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -1,5 +1,21 @@ -package org.sufficientlysecure.keychain.ui.base; +/* + * Copyright (C) 2014-2015 Dominik Schürmann + * + * 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.base; import java.io.IOException; import java.nio.ByteBuffer; @@ -35,7 +51,6 @@ import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Preferences; - public abstract class BaseNfcActivity extends BaseActivity { public static final int REQUEST_CODE_PASSPHRASE = 1; @@ -108,10 +123,10 @@ public abstract class BaseNfcActivity extends BaseActivity { enableNfcForegroundDispatch(); } - protected void obtainYubikeyPin(RequiredInputParcel requiredInput) { + protected void obtainYubiKeyPin(RequiredInputParcel requiredInput) { Preferences prefs = Preferences.getPreferences(this); - if (prefs.useDefaultYubikeyPin()) { + if (prefs.useDefaultYubiKeyPin()) { mPin = new Passphrase("123456"); return; } @@ -123,7 +138,7 @@ public abstract class BaseNfcActivity extends BaseActivity { } - protected void setYubikeyPin(Passphrase pin) { + protected void setYubiKeyPin(Passphrase pin) { mPin = pin; } -- cgit v1.2.3 From e332699c9c67ca29a077c500e840b6005126f92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 15 Apr 2015 10:10:53 +0200 Subject: More cleanup --- .../keychain/ui/CertifyKeyFragment.java | 1 + .../keychain/ui/CryptoOperationFragment.java | 129 --------- .../keychain/ui/DecryptFragment.java | 1 + .../keychain/ui/EditKeyFragment.java | 4 +- .../keychain/ui/EncryptFilesFragment.java | 1 + .../keychain/ui/EncryptTextFragment.java | 1 + .../keychain/ui/NfcIntentActivity.java | 314 --------------------- .../keychain/ui/ViewKeyYubiKeyFragment.java | 22 +- .../keychain/ui/base/BaseNfcActivity.java | 4 +- .../keychain/ui/base/CryptoOperationFragment.java | 131 +++++++++ 10 files changed, 156 insertions(+), 452 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index 20a280a54..59623a610 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -56,6 +56,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter; +import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java deleted file mode 100644 index b136492b4..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * Copyright (C) 2015 Vincent Breitmoser - * - * 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.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.os.Message; -import android.support.v4.app.Fragment; - -import org.sufficientlysecure.keychain.operations.results.InputPendingResult; -import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.service.ServiceProgressHandler; -import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; - -/** - * All fragments executing crypto operations need to extend this class. - */ -public abstract class CryptoOperationFragment extends Fragment { - - public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; - public static final int REQUEST_CODE_NFC = 0x00008002; - - private void initiateInputActivity(RequiredInputParcel requiredInput) { - - switch (requiredInput.mType) { - case NFC_DECRYPT: - case NFC_SIGN: { - Intent intent = new Intent(getActivity(), NfcOperationActivity.class); - intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput); - startActivityForResult(intent, REQUEST_CODE_NFC); - return; - } - - case PASSPHRASE: - case PASSPHRASE_SYMMETRIC: { - Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); - intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput); - startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); - return; - } - } - - throw new RuntimeException("Unhandled pending result!"); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == Activity.RESULT_CANCELED) { - onCryptoOperationCancelled(); - return; - } - - switch (requestCode) { - case REQUEST_CODE_PASSPHRASE: { - if (resultCode == Activity.RESULT_OK && data != null) { - CryptoInputParcel cryptoInput = - data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT); - cryptoOperation(cryptoInput); - return; - } - break; - } - - case REQUEST_CODE_NFC: { - if (resultCode == Activity.RESULT_OK && data != null) { - CryptoInputParcel cryptoInput = - data.getParcelableExtra(NfcOperationActivity.RESULT_DATA); - cryptoOperation(cryptoInput); - return; - } - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - } - } - } - - public boolean handlePendingMessage(Message message) { - - if (message.arg1 == ServiceProgressHandler.MessageStatus.OKAY.ordinal()) { - Bundle data = message.getData(); - - OperationResult result = data.getParcelable(OperationResult.EXTRA_RESULT); - if (result == null || !(result instanceof InputPendingResult)) { - return false; - } - - InputPendingResult pendingResult = (InputPendingResult) result; - if (pendingResult.isPending()) { - RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel(); - initiateInputActivity(requiredInput); - return true; - } - } - - return false; - } - - protected void cryptoOperation() { - cryptoOperation(new CryptoInputParcel()); - } - - protected abstract void cryptoOperation(CryptoInputParcel cryptoInput); - - protected void onCryptoOperationCancelled() { - // Nothing to do here, in most cases - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index 68b758bab..33209be86 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -29,6 +29,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index bf17c2991..390efddce 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -17,8 +17,6 @@ package org.sufficientlysecure.keychain.ui; -import java.util.Date; - import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; @@ -53,7 +51,6 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.ServiceProgressHandler; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; @@ -62,6 +59,7 @@ import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAddedAdapter; +import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.dialog.*; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index ddced7cce..ccb4a6355 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -53,6 +53,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.adapter.SpacesItemDecoration; +import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index 47645099d..b37a2ca79 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -44,6 +44,7 @@ import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java deleted file mode 100644 index a1affbc39..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java +++ /dev/null @@ -1,314 +0,0 @@ -/** - * Copyright (c) 2013-2014 Philipp Jakubeit, Signe Rüsch, Dominik Schürmann - * - * Licensed under the Bouncy Castle License (MIT license). See LICENSE file for details. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.annotation.TargetApi; -import android.app.PendingIntent; -import android.content.Intent; -import android.content.IntentFilter; -import android.nfc.NfcAdapter; -import android.nfc.Tag; -import android.nfc.tech.IsoDep; -import android.os.Build; -import android.os.Bundle; -import android.view.WindowManager; -import android.widget.Toast; - -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.base.BaseActivity; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.Iso7816TLV; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * This class provides a communication interface to OpenPGP applications on ISO SmartCard compliant - * NFC devices. - * - * For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf - */ -@TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) -public class NfcIntentActivity extends BaseActivity { - - // special extra for OpenPgpService - public static final String EXTRA_DATA = "data"; - - private Intent mServiceIntent; - - private static final int TIMEOUT = 100000; - - private NfcAdapter mNfcAdapter; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Log.d(Constants.TAG, "NfcActivity.onCreate"); - - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - - Intent intent = getIntent(); - Bundle data = intent.getExtras(); - String action = intent.getAction(); - - Log.d(Constants.TAG, action); - Log.d(Constants.TAG, intent.getDataString()); - - // TODO check fingerprint - // mFingerprint = data.getByteArray(EXTRA_FINGERPRINT); - - if (!NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) { - Log.d(Constants.TAG, "Action not supported: " + action); - finish(); - } - - try { - Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); - - // Connect to the detected tag, setting a couple of settings - IsoDep isoDep = IsoDep.get(detectedTag); - isoDep.setTimeout(TIMEOUT); // timeout is set to 100 seconds to avoid cancellation during calculation - isoDep.connect(); - - nfcGreet(isoDep); - // nfcPin(isoDep, "yoloswag"); - nfcGetFingerprint(isoDep); - - } catch (IOException e) { - Log.e(Constants.TAG, "IOException!", e); - finish(); - } - } - - @Override - protected void initLayout() { - setContentView(R.layout.nfc_activity); - } - - /** - * Called when the system is about to start resuming a previous activity, - * disables NFC Foreground Dispatch - */ - public void onPause() { - super.onPause(); - Log.d(Constants.TAG, "NfcActivity.onPause"); - - // disableNfcForegroundDispatch(); - } - - /** - * Called when the activity will start interacting with the user, - * enables NFC Foreground Dispatch - */ - public void onResume() { - super.onResume(); - Log.d(Constants.TAG, "NfcActivity.onResume"); - - // enableNfcForegroundDispatch(); - } - - /** Handle NFC communication and return a result. - * - * This method is called by onNewIntent above upon discovery of an NFC tag. - * It handles initialization and login to the application, subsequently - * calls either nfcCalculateSignature() or nfcDecryptSessionKey(), then - * finishes the activity with an appropiate result. - * - * On general communication, see also - * http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_annex-a.aspx - * - * References to pages are generally related to the OpenPGP Application - * on ISO SmartCard Systems specification. - * - */ - private void nfcGreet(IsoDep isoDep) throws IOException { - - // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. - // See specification, page 51 - String accepted = "9000"; - - // Command APDU (page 51) for SELECT FILE command (page 29) - String opening = - "00" // CLA - + "A4" // INS - + "04" // P1 - + "00" // P2 - + "06" // Lc (number of bytes) - + "D27600012401" // Data (6 bytes) - + "00"; // Le - if (!card(isoDep, opening).equals(accepted)) { // activate connection - toast("Opening Error!"); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - } - } - - private void nfcPin(IsoDep isoDep, String pin) throws IOException { - - String data = "00CA006E00"; - String fingerprint = card(isoDep, data); - - // Command APDU for VERIFY command (page 32) - String login = - "00" // CLA - + "20" // INS - + "00" // P1 - + "82" // P2 (PW1) - + String.format("%02x", pin.length()) // Lc - + Hex.toHexString(pin.getBytes()); - if ( ! card(isoDep, login).equals("9000")) { // login - toast("Pin Error!"); - setResult(RESULT_CANCELED, mServiceIntent); - finish(); - } - - } - - /** - * Gets the user ID - * - * @return the user id as "name " - * @throws java.io.IOException - */ - public static String getUserId(IsoDep isoDep) throws IOException { - String info = "00CA006500"; - String data = "00CA005E00"; - return getName(card(isoDep, info)) + " <" + (new String(Hex.decode(getDataField(card(isoDep, data))))) + ">"; - } - - /** - * Gets the long key ID - * - * @return the long key id (last 16 bytes of the fingerprint) - * @throws java.io.IOException - */ - public static long getKeyId(IsoDep isoDep) throws IOException { - String keyId = nfcGetFingerprint(isoDep).substring(24); - Log.d(Constants.TAG, "keyId: " + keyId); - return Long.parseLong(keyId, 16); - } - - /** - * Gets the fingerprint of the signature key - * - * @return the fingerprint - * @throws java.io.IOException - */ - public static String nfcGetFingerprint(IsoDep isoDep) throws IOException { - String data = "00CA006E00"; - byte[] buf = isoDep.transceive(Hex.decode(data)); - - Iso7816TLV tlv = Iso7816TLV.readSingle(buf, true); - Log.d(Constants.TAG, "nfc tlv data:\n" + tlv.prettyPrint()); - - Iso7816TLV fptlv = Iso7816TLV.findRecursive(tlv, 0xc5); - if (fptlv != null) { - ByteBuffer fpbuf = ByteBuffer.wrap(fptlv.mV); - byte[] fp = new byte[20]; - fpbuf.get(fp); - Log.d(Constants.TAG, "fingerprint 1: " + KeyFormattingUtils.convertFingerprintToHex(fp)); - fpbuf.get(fp); - Log.d(Constants.TAG, "fingerprint 2: " + KeyFormattingUtils.convertFingerprintToHex(fp)); - fpbuf.get(fp); - Log.d(Constants.TAG, "fingerprint 3: " + KeyFormattingUtils.convertFingerprintToHex(fp)); - } - - return "nope"; - } - - /** - * Prints a message to the screen - * - * @param text the text which should be contained within the toast - */ - private void toast(String text) { - Toast.makeText(this, text, Toast.LENGTH_LONG).show(); - } - - /** - * Receive new NFC Intents to this activity only by enabling foreground dispatch. - * This can only be done in onResume! - */ - public void enableNfcForegroundDispatch() { - mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - Intent nfcI = new Intent(this, NfcIntentActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); - PendingIntent nfcPendingIntent = PendingIntent.getActivity(this, 0, nfcI, 0); - IntentFilter[] writeTagFilters = new IntentFilter[]{ - new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED) - }; - - // https://code.google.com/p/android/issues/detail?id=62918 - // maybe mNfcAdapter.enableReaderMode(); ? - try { - mNfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null); - } catch (IllegalStateException e) { - Log.i(Constants.TAG, "NfcForegroundDispatch Error!", e); - } - Log.d(Constants.TAG, "NfcForegroundDispatch has been enabled!"); - } - - /** - * Disable foreground dispatch in onPause! - */ - public void disableNfcForegroundDispatch() { - mNfcAdapter.disableForegroundDispatch(this); - Log.d(Constants.TAG, "NfcForegroundDispatch has been disabled!"); - } - - /** - * Gets the name of the user out of the raw card output regarding card holder related data - * - * @param name the raw card holder related data from the card - * @return the name given in this data - */ - public static String getName(String name) { - String slength; - int ilength; - name = name.substring(6); - slength = name.substring(0, 2); - ilength = Integer.parseInt(slength, 16) * 2; - name = name.substring(2, ilength + 2); - name = (new String(Hex.decode(name))).replace('<', ' '); - return (name); - } - - /** - * Reduces the raw data from the card by four characters - * - * @param output the raw data from the card - * @return the data field of that data - */ - private static String getDataField(String output) { - return output.substring(0, output.length() - 4); - } - - /** - * Communicates with the OpenPgpCard via the APDU - * - * @param hex the hexadecimal APDU - * @return The answer from the card - * @throws java.io.IOException throws an exception if something goes wrong - */ - public static String card(IsoDep isoDep, String hex) throws IOException { - return getHex(isoDep.transceive(Hex.decode(hex))); - } - - /** - * Converts a byte array into an hex string - * - * @param raw the byte array representation - * @return the hexadecimal string representation - */ - public static String getHex(byte[] raw) { - return new String(Hex.encode(raw)); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java index a2c158e7d..812874456 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyYubiKeyFragment.java @@ -1,5 +1,22 @@ -package org.sufficientlysecure.keychain.ui; +/* + * Copyright (C) 2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser + * + * 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 java.nio.ByteBuffer; import java.util.Arrays; @@ -30,7 +47,6 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.ServiceProgressHandler; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; - public class ViewKeyYubiKeyFragment extends Fragment implements LoaderCallbacks { @@ -45,7 +61,6 @@ public class ViewKeyYubiKeyFragment extends Fragment private TextView vStatus; public static ViewKeyYubiKeyFragment newInstance(byte[] fingerprints, String userId, byte[] aid) { - ViewKeyYubiKeyFragment frag = new ViewKeyYubiKeyFragment(); Bundle args = new Bundle(); @@ -55,7 +70,6 @@ public class ViewKeyYubiKeyFragment extends Fragment frag.setArguments(args); return frag; - } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java index f55c8b17a..95c1690b1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java @@ -1,5 +1,6 @@ /* - * Copyright (C) 2014-2015 Dominik Schürmann + * Copyright (C) 2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser * * 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 @@ -213,7 +214,6 @@ public abstract class BaseNfcActivity extends BaseActivity { final String nfcUserId = nfcGetUserId(); final byte[] nfcAid = nfcGetAid(); - String fp = KeyFormattingUtils.convertFingerprintToHex(nfcFingerprints); final long masterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(nfcFingerprints); try { 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 new file mode 100644 index 000000000..232a39f86 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * Copyright (C) 2015 Vincent Breitmoser + * + * 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.base; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Message; +import android.support.v4.app.Fragment; + +import org.sufficientlysecure.keychain.operations.results.InputPendingResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +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.PassphraseDialogActivity; + +/** + * All fragments executing crypto operations need to extend this class. + */ +public abstract class CryptoOperationFragment extends Fragment { + + public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; + public static final int REQUEST_CODE_NFC = 0x00008002; + + private void initiateInputActivity(RequiredInputParcel requiredInput) { + + switch (requiredInput.mType) { + case NFC_DECRYPT: + case NFC_SIGN: { + Intent intent = new Intent(getActivity(), NfcOperationActivity.class); + intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput); + startActivityForResult(intent, REQUEST_CODE_NFC); + return; + } + + case PASSPHRASE: + case PASSPHRASE_SYMMETRIC: { + Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); + intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput); + startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); + return; + } + } + + throw new RuntimeException("Unhandled pending result!"); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == Activity.RESULT_CANCELED) { + onCryptoOperationCancelled(); + return; + } + + switch (requestCode) { + case REQUEST_CODE_PASSPHRASE: { + if (resultCode == Activity.RESULT_OK && data != null) { + CryptoInputParcel cryptoInput = + data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT); + cryptoOperation(cryptoInput); + return; + } + break; + } + + case REQUEST_CODE_NFC: { + if (resultCode == Activity.RESULT_OK && data != null) { + CryptoInputParcel cryptoInput = + data.getParcelableExtra(NfcOperationActivity.RESULT_DATA); + cryptoOperation(cryptoInput); + return; + } + break; + } + + default: { + super.onActivityResult(requestCode, resultCode, data); + } + } + } + + public boolean handlePendingMessage(Message message) { + + if (message.arg1 == ServiceProgressHandler.MessageStatus.OKAY.ordinal()) { + Bundle data = message.getData(); + + OperationResult result = data.getParcelable(OperationResult.EXTRA_RESULT); + if (result == null || !(result instanceof InputPendingResult)) { + return false; + } + + InputPendingResult pendingResult = (InputPendingResult) result; + if (pendingResult.isPending()) { + RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel(); + initiateInputActivity(requiredInput); + return true; + } + } + + return false; + } + + protected void cryptoOperation() { + cryptoOperation(new CryptoInputParcel()); + } + + protected abstract void cryptoOperation(CryptoInputParcel cryptoInput); + + protected void onCryptoOperationCancelled() { + // Nothing to do here, in most cases + } + +} -- cgit v1.2.3 From b440456acc1e846f19f663a2987cb1bc292f14bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 15 Apr 2015 10:25:56 +0200 Subject: Use portrait mode for qr code scanning --- .../keychain/ui/ImportKeysProxyActivity.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java index 21747f77b..b9f1bf870 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui; import android.annotation.TargetApi; import android.app.ProgressDialog; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NfcAdapter; @@ -83,25 +84,22 @@ public class ImportKeysProxyActivity extends FragmentActivity { returnResult = false; processScannedContent(dataUri); - } else if (ACTION_SCAN_IMPORT.equals(action)) { + } else if (ACTION_SCAN_IMPORT.equals(action) || ACTION_QR_CODE_API.equals(action)) { returnResult = false; IntentIntegrator integrator = new IntentIntegrator(this); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES) .setPrompt(getString(R.string.import_qr_code_text)) - .setResultDisplayDuration(0) - .initiateScan(); + .setResultDisplayDuration(0); + integrator.setOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + integrator.initiateScan(); } else if (ACTION_SCAN_WITH_RESULT.equals(action)) { returnResult = true; IntentIntegrator integrator = new IntentIntegrator(this); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES) .setPrompt(getString(R.string.import_qr_code_text)) - .setResultDisplayDuration(0) - .initiateScan(); - } else if (ACTION_QR_CODE_API.equals(action)) { - // scan using xzing's Barcode Scanner from outside OpenKeychain - - returnResult = false; - new IntentIntegrator(this).initiateScan(); + .setResultDisplayDuration(0); + integrator.setOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + integrator.initiateScan(); } else if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { // Check to see if the Activity started due to an Android Beam if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { -- cgit v1.2.3