From de698b89552a02a445f808cf97d3ce94d35a2777 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 29 Jun 2014 22:34:53 +0200 Subject: add create key capabilities to SaveKeyringParcel --- .../keychain/pgp/PgpKeyOperation.java | 76 +++++++++++++++++++--- .../keychain/pgp/WrappedSecretKeyRing.java | 26 -------- .../keychain/service/KeychainIntentService.java | 44 ++++++++----- .../keychain/service/OperationResultParcel.java | 5 ++ .../keychain/service/SaveKeyringParcel.java | 25 ++++--- OpenKeychain/src/main/res/values/strings.xml | 2 + .../src/test/java/tests/PgpDecryptVerifyTest.java | 1 - 7 files changed, 118 insertions(+), 61 deletions(-) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 1b59e7cc0..bde79eee0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -38,6 +38,7 @@ import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; import org.spongycastle.openpgp.operator.PGPContentSignerBuilder; import org.spongycastle.openpgp.operator.PGPDigestCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; @@ -50,6 +51,8 @@ import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel; import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType; import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd; +import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Primes; import java.io.IOException; @@ -175,6 +178,40 @@ public class PgpKeyOperation { } } + public UncachedKeyRing createSecretKeyRing(SaveKeyringParcel saveParcel, OperationLog log, + int indent) { + + try { + + log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_KEYID, indent); + indent += 1; + updateProgress(R.string.progress_building_key, 0, 100); + + if (saveParcel.addSubKeys == null || saveParcel.addSubKeys.isEmpty()) { + log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_MASTER, indent); + return null; + } + + SubkeyAdd add = saveParcel.addSubKeys.remove(0); + PGPSecretKey masterSecretKey = createKey(add.mAlgorithm, add.mKeysize, + saveParcel.newPassphrase, true); + PGPSecretKeyRing sKR = new PGPSecretKeyRing( + masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator()); + + return internal(sKR, masterSecretKey, saveParcel, saveParcel.newPassphrase, log, indent); + + } catch (PGPException e) { + Log.e(Constants.TAG, "pgp error encoding key", e); + return null; + } catch (IOException e) { + Log.e(Constants.TAG, "io error encoding key", e); + return null; + } catch (PgpGeneralMsgIdException e) { + return null; + } + + } + /** This method introduces a list of modifications specified by a SaveKeyringParcel to a * WrappedSecretKeyRing. * @@ -204,28 +241,49 @@ public class PgpKeyOperation { indent += 1; updateProgress(R.string.progress_building_key, 0, 100); + // Make sure this is called with a proper SaveKeyringParcel + if (saveParcel.mMasterKeyId == null || saveParcel.mMasterKeyId != wsKR.getMasterKeyId()) { + log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_KEYID, indent); + return null; + } + // We work on bouncycastle object level here PGPSecretKeyRing sKR = wsKR.getRing(); - PGPPublicKey masterPublicKey = sKR.getPublicKey(); PGPSecretKey masterSecretKey = sKR.getSecretKey(); + // Make sure the fingerprint matches + if (saveParcel.mFingerprint == null + || !Arrays.equals(saveParcel.mFingerprint, + masterSecretKey.getPublicKey().getFingerprint())) { + log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_FINGERPRINT, indent); + return null; + } + + return internal(sKR, masterSecretKey, saveParcel, passphrase, log, indent); + + } + + private UncachedKeyRing internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey, + SaveKeyringParcel saveParcel, String passphrase, + OperationLog log, int indent) { + + updateProgress(R.string.progress_certifying_master_key, 20, 100); + + PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey(); + // 1. Unlock private key log.add(LogLevel.DEBUG, LogType.MSG_MF_UNLOCK, indent); - PGPPrivateKey masterPrivateKey; { + PGPPrivateKey masterPrivateKey; + { try { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor); } catch (PGPException e) { - log.add(LogLevel.ERROR, LogType.MSG_MF_UNLOCK_ERROR, indent+1); + log.add(LogLevel.ERROR, LogType.MSG_MF_UNLOCK_ERROR, indent + 1); return null; } } - if (!Arrays.equals(saveParcel.mFingerprint, sKR.getPublicKey().getFingerprint())) { - return null; - } - - updateProgress(R.string.progress_certifying_master_key, 20, 100); // work on master secret key try { @@ -262,7 +320,7 @@ public class PgpKeyOperation { } - // 4a. For each subkey change, generate new subkey binding certificate + // 4a. For each subkey change, generate new subkey binding certificate for (SaveKeyringParcel.SubkeyChange change : saveParcel.changeSubKeys) { log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_CHANGE, indent, PgpKeyHelper.convertKeyIdToHex(change.mKeyId)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java index d7148f710..c737b7c46 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java @@ -8,16 +8,13 @@ import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; -import java.security.NoSuchProviderException; import java.util.Iterator; public class WrappedSecretKeyRing extends WrappedKeyRing { @@ -91,29 +88,6 @@ public class WrappedSecretKeyRing extends WrappedKeyRing { } } - public UncachedKeyRing changeSecretKeyPassphrase(String oldPassphrase, - String newPassphrase) - throws IOException, PGPException, NoSuchProviderException { - - if (oldPassphrase == null) { - oldPassphrase = ""; - } - if (newPassphrase == null) { - newPassphrase = ""; - } - - PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword( - mRing, - new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray()), - new JcePBESecretKeyEncryptorBuilder(mRing.getSecretKey() - .getKeyEncryptionAlgorithm()).build(newPassphrase.toCharArray())); - - return new UncachedKeyRing(newKeyRing); - - } - public IterableIterator secretKeyIterator() { final Iterator it = mRing.getSecretKeys(); return new IterableIterator(new Iterator() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index e1514b16f..4fbdfab76 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -209,6 +209,10 @@ public class KeychainIntentService extends IntentService mMessenger = (Messenger) extras.get(EXTRA_MESSENGER); Bundle data = extras.getBundle(EXTRA_DATA); + if (data == null) { + Log.e(Constants.TAG, "data extra is null!"); + return; + } OtherHelper.logDebugBundle(data, "EXTRA_DATA"); @@ -320,33 +324,40 @@ public class KeychainIntentService extends IntentService try { /* Input */ SaveKeyringParcel saveParcel = data.getParcelable(SAVE_KEYRING_PARCEL); - long masterKeyId = saveParcel.mMasterKeyId; + if (saveParcel == null) { + Log.e(Constants.TAG, "bug: missing save_keyring_parcel in data!"); + return; + } /* Operation */ ProviderHelper providerHelper = new ProviderHelper(this); PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 10, 50, 100)); try { - String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE); - WrappedSecretKeyRing secRing = providerHelper.getWrappedSecretKeyRing(masterKeyId); - OperationLog log = new OperationLog(); - UncachedKeyRing ring = keyOperations.modifySecretKeyRing(secRing, saveParcel, - passphrase, log, 0); - providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100)); + UncachedKeyRing ring; + if (saveParcel.mMasterKeyId != null) { + String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE); + WrappedSecretKeyRing secRing = + providerHelper.getWrappedSecretKeyRing(saveParcel.mMasterKeyId); + + ring = keyOperations.modifySecretKeyRing(secRing, saveParcel, + passphrase, log, 0); + } else { + ring = keyOperations.createSecretKeyRing(saveParcel, log, 0); + } + + providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 10, 95, 100)); + + if (saveParcel.newPassphrase != null) { + PassphraseCacheService.addCachedPassphrase(this, ring.getMasterKeyId(), + saveParcel.newPassphrase); + } } catch (ProviderHelper.NotFoundException e) { - // UncachedKeyRing ring = keyOperations.(saveParcel); //new Keyring - // save the pair - setProgress(R.string.progress_saving_key_ring, 95, 100); - // providerHelper.saveSecretKeyRing(ring); sendErrorToHandler(e); } setProgress(R.string.progress_done, 100, 100); - if (saveParcel.newPassphrase != null) { - PassphraseCacheService.addCachedPassphrase(this, masterKeyId, saveParcel.newPassphrase); - } - /* Output */ sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); } catch (Exception e) { @@ -437,7 +448,7 @@ public class KeychainIntentService extends IntentService new FileOutputStream(outputFile)); if (mIsCanceled) { - boolean isDeleted = new File(outputFile).delete(); + new File(outputFile).delete(); } sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); @@ -593,6 +604,7 @@ public class KeychainIntentService extends IntentService return; } Message msg = Message.obtain(); + assert msg != null; msg.arg1 = arg1; if (arg2 != null) { msg.arg2 = arg2; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java index 7f91ab490..535fa08cf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java @@ -233,9 +233,14 @@ public class OperationResultParcel implements Parcelable { MSG_MG_NEW_SUBKEY (R.string.msg_mg_new_subkey), MSG_MG_FOUND_NEW (R.string.msg_mg_found_new), + // secret key create + MSG_CR_ERROR_NO_MASTER (R.string.msg_mr), + // secret key modify MSG_MF (R.string.msg_mr), MSG_MF_ERROR_ENCODE (R.string.msg_mf_error_encode), + MSG_MF_ERROR_FINGERPRINT (R.string.msg_mf_error_fingerprint), + MSG_MF_ERROR_KEYID (R.string.msg_mf_error_keyid), MSG_MF_ERROR_PGP (R.string.msg_mf_error_pgp), MSG_MF_ERROR_SIG (R.string.msg_mf_error_sig), MSG_MF_PASSPHRASE (R.string.msg_mf_passphrase), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index 020b808b9..1ad19cdd0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -22,10 +22,10 @@ import java.util.ArrayList; */ public class SaveKeyringParcel implements Parcelable { - // the master key id to be edited - public final long mMasterKeyId; - // the key fingerprint, for safety - public final byte[] mFingerprint; + // the master key id to be edited. if this is null, a new one will be created + public Long mMasterKeyId; + // the key fingerprint, for safety. MUST be null for a new key. + public byte[] mFingerprint; public String newPassphrase; @@ -38,9 +38,7 @@ public class SaveKeyringParcel implements Parcelable { public ArrayList revokeUserIds; public ArrayList revokeSubKeys; - public SaveKeyringParcel(long masterKeyId, byte[] fingerprint) { - mMasterKeyId = masterKeyId; - mFingerprint = fingerprint; + public SaveKeyringParcel() { addUserIds = new ArrayList(); addSubKeys = new ArrayList(); changeSubKeys = new ArrayList(); @@ -48,6 +46,12 @@ public class SaveKeyringParcel implements Parcelable { revokeSubKeys = new ArrayList(); } + public SaveKeyringParcel(long masterKeyId, byte[] fingerprint) { + this(); + mMasterKeyId = masterKeyId; + mFingerprint = fingerprint; + } + // performance gain for using Parcelable here would probably be negligible, // use Serializable instead. public static class SubkeyAdd implements Serializable { @@ -75,7 +79,7 @@ public class SaveKeyringParcel implements Parcelable { } public SaveKeyringParcel(Parcel source) { - mMasterKeyId = source.readLong(); + mMasterKeyId = source.readInt() != 0 ? source.readLong() : null; mFingerprint = source.createByteArray(); addUserIds = source.createStringArrayList(); @@ -90,7 +94,10 @@ public class SaveKeyringParcel implements Parcelable { @Override public void writeToParcel(Parcel destination, int flags) { - destination.writeLong(mMasterKeyId); + destination.writeInt(mMasterKeyId == null ? 0 : 1); + if(mMasterKeyId != null) { + destination.writeLong(mMasterKeyId); + } destination.writeByteArray(mFingerprint); destination.writeStringList(addUserIds); diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 39b105664..d886fe241 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -626,6 +626,8 @@ Modifying keyring %s Encoding exception! + Actual key fingerprint does not match expected! + No keyid. This is a programming error, please file a bug report! PGP internal exception! Signature exception! Changing passphrase diff --git a/OpenKeychain/src/test/java/tests/PgpDecryptVerifyTest.java b/OpenKeychain/src/test/java/tests/PgpDecryptVerifyTest.java index 346a1f9df..d759bce05 100644 --- a/OpenKeychain/src/test/java/tests/PgpDecryptVerifyTest.java +++ b/OpenKeychain/src/test/java/tests/PgpDecryptVerifyTest.java @@ -22,7 +22,6 @@ public class PgpDecryptVerifyTest { Assert.assertEquals(expectedSignatureResult, status); } - @Test public void testVerifyFailure() throws Exception { -- cgit v1.2.3 From 7408a35e1984c4791ce956bdc2ba225f8e0c3a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 1 Jul 2014 12:36:02 +0200 Subject: edit key: part 3 --- .../keychain/ui/EditKeyFragment.java | 65 ++++---- .../keychain/ui/adapter/UserIdsArrayAdapter.java | 131 ---------------- .../keychain/ui/adapter/UserIdsNewAdapter.java | 146 ++++++++++++++++++ .../ui/dialog/AddUserIdDialogFragment.java | 165 --------------------- .../src/main/res/layout/add_user_id_dialog.xml | 60 -------- 5 files changed, 180 insertions(+), 387 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsNewAdapter.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java delete mode 100644 OpenKeychain/src/main/res/layout/add_user_id_dialog.xml (limited to 'OpenKeychain/src') 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 b6a95a517..079263e64 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -51,7 +51,7 @@ import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; -import org.sufficientlysecure.keychain.ui.adapter.UserIdsArrayAdapter; +import org.sufficientlysecure.keychain.ui.adapter.UserIdsNewAdapter; import org.sufficientlysecure.keychain.ui.dialog.AddUserIdDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; @@ -76,7 +76,7 @@ public class EditKeyFragment extends LoaderFragment implements private UserIdsAdapter mUserIdsAdapter; private SubkeysAdapter mKeysAdapter; - private UserIdsArrayAdapter mUserIdsAddedAdapter; + private UserIdsNewAdapter mUserIdsAddedAdapter; private Uri mDataUri; @@ -189,7 +189,7 @@ public class EditKeyFragment extends LoaderFragment implements } }); - mUserIdsAddedAdapter = new UserIdsArrayAdapter(getActivity()); + mUserIdsAddedAdapter = new UserIdsNewAdapter(getActivity()); mUserIdsAddedList.setAdapter(mUserIdsAddedAdapter); mUserIdsAddedAdapter.setData(mSaveKeyringParcel.addUserIds); @@ -321,34 +321,37 @@ public class EditKeyFragment extends LoaderFragment implements } private void addUserId() { - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case AddUserIdDialogFragment.MESSAGE_OKAY: - Bundle data = message.getData(); - String userId = data.getString(AddUserIdDialogFragment.MESSAGE_DATA_USER_ID); - - if (userId != null) { - mSaveKeyringParcel.addUserIds.add(userId); - mUserIdsAddedAdapter.setData(mSaveKeyringParcel.addUserIds); - } - } - getLoaderManager().getLoader(LOADER_ID_USER_IDS).forceLoad(); - } - }; - - // Create a new Messenger for the communication back - final Messenger messenger = new Messenger(returnHandler); - - DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { - public void run() { - AddUserIdDialogFragment dialogFragment = - AddUserIdDialogFragment.newInstance(messenger); - - dialogFragment.show(getActivity().getSupportFragmentManager(), "addUserIdDialog"); - } - }); +// mSaveKeyringParcel.addUserIds.add(userId); +// mUserIdsAddedAdapter.setData(mSaveKeyringParcel.addUserIds); + + +// Handler returnHandler = new Handler() { +// @Override +// public void handleMessage(Message message) { +// switch (message.what) { +// case AddUserIdDialogFragment.MESSAGE_OKAY: +// Bundle data = message.getData(); +// String userId = data.getString(AddUserIdDialogFragment.MESSAGE_DATA_USER_ID); +// +// if (userId != null) { + +// } +// } +// getLoaderManager().getLoader(LOADER_ID_USER_IDS).forceLoad(); +// } +// }; +// +// // Create a new Messenger for the communication back +// final Messenger messenger = new Messenger(returnHandler); +// +// DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { +// public void run() { +// AddUserIdDialogFragment dialogFragment = +// AddUserIdDialogFragment.newInstance(messenger); +// +// dialogFragment.show(getActivity().getSupportFragmentManager(), "addUserIdDialog"); +// } +// }); } private void save() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java deleted file mode 100644 index e6445c074..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2013-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.adapter; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Context; -import android.os.Build; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.KeyRing; - -import java.util.List; - -public class UserIdsArrayAdapter extends ArrayAdapter { - protected LayoutInflater mInflater; - protected Activity mActivity; - - protected List mData; - - static class ViewHolder { - public TextView vName; - public TextView vAddress; - public TextView vComment; - public ImageView vVerified; - public ImageView vHasChanges; - public CheckBox vCheckBox; - } - - public UserIdsArrayAdapter(Activity activity) { - super(activity, -1); - mActivity = activity; - mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public void setData(List data) { - clear(); - if (data != null) { - this.mData = data; - - // add data to extended ArrayAdapter - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - addAll(data); - } else { - for (String entry : data) { - add(entry); - } - } - } - } - - public List getData() { - return mData; - } - - @Override - public boolean hasStableIds() { - return true; - } - - public View getView(int position, View convertView, ViewGroup parent) { - String entry = mData.get(position); - ViewHolder holder; - if (convertView == null) { - holder = new ViewHolder(); - convertView = mInflater.inflate(R.layout.view_key_userids_item, null); - holder.vName = (TextView) convertView.findViewById(R.id.userId); - holder.vAddress = (TextView) convertView.findViewById(R.id.address); - holder.vComment = (TextView) convertView.findViewById(R.id.comment); - holder.vVerified = (ImageView) convertView.findViewById(R.id.certified); - holder.vHasChanges = (ImageView) convertView.findViewById(R.id.has_changes); - holder.vCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox); - convertView.setTag(holder); - } else { - holder = (ViewHolder) convertView.getTag(); - } - - // user id - String[] splitUserId = KeyRing.splitUserId(entry); - if (splitUserId[0] != null) { - holder.vName.setText(splitUserId[0]); - } else { - holder.vName.setText(R.string.user_id_no_name); - } - if (splitUserId[1] != null) { - holder.vAddress.setText(splitUserId[1]); - holder.vAddress.setVisibility(View.VISIBLE); - } else { - holder.vAddress.setVisibility(View.GONE); - } - if (splitUserId[2] != null) { - holder.vComment.setText(splitUserId[2]); - holder.vComment.setVisibility(View.VISIBLE); - } else { - holder.vComment.setVisibility(View.GONE); - } - - holder.vCheckBox.setVisibility(View.GONE); - - holder.vVerified.setImageResource(R.drawable.key_certify_ok_depth0); - - // all items are "new" - holder.vHasChanges.setVisibility(View.VISIBLE); - - return convertView; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsNewAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsNewAdapter.java new file mode 100644 index 000000000..dffce50a4 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsNewAdapter.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2013-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.adapter; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.os.Build; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.KeyRing; + +import java.util.List; + +public class UserIdsNewAdapter extends ArrayAdapter { + protected LayoutInflater mInflater; + protected Activity mActivity; + + protected List mData; + +// static class ViewHolder { +// public TextView vName; +// public TextView vAddress; +// public TextView vComment; +// public ImageView vVerified; +// public ImageView vHasChanges; +// public CheckBox vCheckBox; +// } + + public UserIdsNewAdapter(Activity activity) { + super(activity, -1); + mActivity = activity; + mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public void setData(List data) { + clear(); + if (data != null) { + this.mData = data; + + // add data to extended ArrayAdapter + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + addAll(data); + } else { + for (String entry : data) { + add(entry); + } + } + } + } + + public List getData() { +// String name = mName.getText().toString(); +// - String email = mAddress.getText().toString(); +// - String comment = mComment.getText().toString(); +// - +// - String userId = null; +// - if (!TextUtils.isEmpty(name)) { +// - userId = name; +// - if (!TextUtils.isEmpty(comment)) { +// - userId += " (" + comment + ")"; +// - } +// - if (!TextUtils.isEmpty(email)) { +// - userId += " <" + email + ">"; +// - } +// - } + return mData; + } + + @Override + public boolean hasStableIds() { + return true; + } + + public View getView(int position, View convertView, ViewGroup parent) { + String entry = mData.get(position); +// ViewHolder holder; +// if (convertView == null) { +// holder = new ViewHolder(); + convertView = mInflater.inflate(R.layout.edit_key_new_userids_item, null); + EditText vName = (EditText) convertView.findViewById(R.id.userId); + EditText vAddress = (EditText) convertView.findViewById(R.id.address); + EditText vComment = (EditText) convertView.findViewById(R.id.comment); +// holder.vVerified = (ImageView) convertView.findViewById(R.id.certified); + ImageView vHasChanges = (ImageView) convertView.findViewById(R.id.has_changes); +// holder.vCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox); +// convertView.setTag(holder); +// } else { +// holder = (ViewHolder) convertView.getTag(); +// } + +// // user id +// String[] splitUserId = KeyRing.splitUserId(entry); +// if (splitUserId[0] != null) { +// vName.setText(splitUserId[0]); +// } else { +// vName.setText(R.string.user_id_no_name); +// } +// if (splitUserId[1] != null) { +// vAddress.setText(splitUserId[1]); +// vAddress.setVisibility(View.VISIBLE); +// } else { +// holder.vAddress.setVisibility(View.GONE); +// } +// if (splitUserId[2] != null) { +// vComment.setText(splitUserId[2]); +// vComment.setVisibility(View.VISIBLE); +// } else { +// holder.vComment.setVisibility(View.GONE); +// } +// +// holder.vCheckBox.setVisibility(View.GONE); +// +// holder.vVerified.setImageResource(R.drawable.key_certify_ok_depth0); +// +// // all items are "new" +// holder.vHasChanges.setVisibility(View.VISIBLE); + + return convertView; + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java deleted file mode 100644 index c27266e3f..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java +++ /dev/null @@ -1,165 +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.dialog; - -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.support.v4.app.DialogFragment; -import android.text.TextUtils; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.view.inputmethod.EditorInfo; -import android.widget.EditText; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Log; - -public class AddUserIdDialogFragment extends DialogFragment implements EditText.OnEditorActionListener { - private static final String ARG_MESSENGER = "messenger"; - - public static final int MESSAGE_OKAY = 1; - - public static final String MESSAGE_DATA_USER_ID = "user_id"; - - private Messenger mMessenger; - - EditText mName; - EditText mAddress; - EditText mComment; - - /** - * Creates new instance of this dialog fragment - */ - public static AddUserIdDialogFragment newInstance(Messenger messenger) { - AddUserIdDialogFragment frag = new AddUserIdDialogFragment(); - Bundle args = new Bundle(); - args.putParcelable(ARG_MESSENGER, messenger); - - frag.setArguments(args); - - return frag; - } - - /** - * Creates dialog - */ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - mMessenger = getArguments().getParcelable(ARG_MESSENGER); - - CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(getActivity()); - LayoutInflater inflater = getActivity().getLayoutInflater(); - View view = inflater.inflate(R.layout.add_user_id_dialog, null); - alert.setView(view); - alert.setTitle("Add Identity"); - - mName = (EditText) view.findViewById(R.id.name); - mAddress = (EditText) view.findViewById(R.id.address); - mComment = (EditText) view.findViewById(R.id.comment); - - alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - done(); - } - }); - - alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - - - return alert.show(); - } - - @Override - public void onActivityCreated(Bundle arg0) { - super.onActivityCreated(arg0); - // Show soft keyboard automatically - mName.requestFocus(); - getDialog().getWindow().setSoftInputMode( - WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - mComment.setOnEditorActionListener(this); - } - - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (EditorInfo.IME_ACTION_DONE == actionId) { - done(); - return true; - } - return false; - } - - private void done() { - String name = mName.getText().toString(); - String email = mAddress.getText().toString(); - String comment = mComment.getText().toString(); - - String userId = null; - if (!TextUtils.isEmpty(name)) { - userId = name; - if (!TextUtils.isEmpty(comment)) { - userId += " (" + comment + ")"; - } - if (!TextUtils.isEmpty(email)) { - userId += " <" + email + ">"; - } - } - Bundle data = new Bundle(); - data.putString(MESSAGE_DATA_USER_ID, userId); - sendMessageToHandler(MESSAGE_OKAY, data); - - this.dismiss(); - } - - /** - * Send message back to handler which is initialized in a activity - * - * @param what Message integer you want to send - */ - private void sendMessageToHandler(Integer what, Bundle data) { - Message msg = Message.obtain(); - msg.what = what; - if (data != null) { - msg.setData(data); - } - - try { - mMessenger.send(msg); - } catch (RemoteException e) { - Log.w(Constants.TAG, "Exception sending message, Is handler present?", e); - } catch (NullPointerException e) { - Log.w(Constants.TAG, "Messenger is null!", e); - } - } - -} diff --git a/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml b/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml deleted file mode 100644 index 502ca1c70..000000000 --- a/OpenKeychain/src/main/res/layout/add_user_id_dialog.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file -- cgit v1.2.3 From 287b74885e68ef1d922fc3178f9f446440c4e530 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 2 Jul 2014 14:51:11 +0200 Subject: don't use zero plural string for english closes #703 --- .../org/sufficientlysecure/keychain/provider/ProviderHelper.java | 6 +++++- OpenKeychain/src/main/res/values/strings.xml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 28495d51d..b5609a327 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -405,7 +405,11 @@ public class ProviderHelper { // classify and order user ids. primary are moved to the front, revoked to the back, // otherwise the order in the keyfile is preserved. - log(LogLevel.INFO, LogType.MSG_IP_UID_CLASSIFYING, trustedKeys.size()); + if (trustedKeys.size() == 0) { + log(LogLevel.INFO, LogType.MSG_IP_UID_CLASSIFYING_ZERO); + } else { + log(LogLevel.INFO, LogType.MSG_IP_UID_CLASSIFYING, trustedKeys.size()); + } mIndent += 1; List uids = new ArrayList(); for (String userId : new IterableIterator( diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 39b105664..54ce523ce 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -546,8 +546,8 @@ Ignoring one certificate issued by an unknown public key Ignoring %s certificates issued by unknown public keys + Classifying user ids (no trusted keys available) - Classifying user ids (no trusted keys available) Classifying user ids (using one trusted key) Classifying user ids (using %s trusted keys) -- cgit v1.2.3 From 144a10a3d043686755651852419c5a8bc6619f2a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 2 Jul 2014 14:53:25 +0200 Subject: forgot a line in previous commit --- .../org/sufficientlysecure/keychain/service/OperationResultParcel.java | 1 + 1 file changed, 1 insertion(+) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java index 7f91ab490..575180505 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java @@ -165,6 +165,7 @@ public class OperationResultParcel implements Parcelable { MSG_IP_UID_CERT_ERROR (R.string.msg_ip_uid_cert_error), MSG_IP_UID_CERT_GOOD (R.string.msg_ip_uid_cert_good), MSG_IP_UID_CERTS_UNKNOWN (R.plurals.msg_ip_uid_certs_unknown), + MSG_IP_UID_CLASSIFYING_ZERO (R.string.msg_ip_uid_classifying_zero), MSG_IP_UID_CLASSIFYING (R.plurals.msg_ip_uid_classifying), MSG_IP_UID_REORDER(R.string.msg_ip_uid_reorder), MSG_IP_UID_PROCESSING (R.string.msg_ip_uid_processing), -- cgit v1.2.3 From 9fb92c8642faf9338a13459a717892edbea0855e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 2 Jul 2014 15:03:28 +0200 Subject: fix subkey addition --- .../keychain/pgp/PgpKeyOperation.java | 96 +++++++++++++--------- .../service/KeychainIntentServiceHandler.java | 3 + 2 files changed, 62 insertions(+), 37 deletions(-) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index bde79eee0..528d36da2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -102,18 +102,13 @@ public class PgpKeyOperation { } /** Creates new secret key. */ - private PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase, - boolean isMasterKey) throws PgpGeneralMsgIdException { + private PGPKeyPair createKey(int algorithmChoice, int keySize) throws PgpGeneralMsgIdException { try { if (keySize < 512) { throw new PgpGeneralMsgIdException(R.string.error_key_size_minimum512bit); } - if (passphrase == null) { - passphrase = ""; - } - int algorithm; KeyPairGenerator keyGen; @@ -126,9 +121,6 @@ public class PgpKeyOperation { } case Constants.choice.algorithm.elgamal: { - if (isMasterKey) { - throw new PgpGeneralMsgIdException(R.string.error_master_key_must_not_be_el_gamal); - } keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME); BigInteger p = Primes.getBestPrime(keySize); BigInteger g = new BigInteger("2"); @@ -154,19 +146,8 @@ public class PgpKeyOperation { } // build new key pair - PGPKeyPair keyPair = new JcaPGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date()); - - // define hashing and signing algos - PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get( - HashAlgorithmTags.SHA1); - - // Build key encrypter and decrypter based on passphrase - PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( - PGPEncryptedData.CAST5, sha1Calc) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); + return new JcaPGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date()); - return new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(), - sha1Calc, isMasterKey, keyEncryptor); } catch(NoSuchProviderException e) { throw new RuntimeException(e); } catch(NoSuchAlgorithmException e) { @@ -193,12 +174,26 @@ public class PgpKeyOperation { } SubkeyAdd add = saveParcel.addSubKeys.remove(0); - PGPSecretKey masterSecretKey = createKey(add.mAlgorithm, add.mKeysize, - saveParcel.newPassphrase, true); + PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize); + + if (add.mAlgorithm == Constants.choice.algorithm.elgamal) { + throw new PgpGeneralMsgIdException(R.string.error_master_key_must_not_be_el_gamal); + } + + // define hashing and signing algos + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder() + .build().get(HashAlgorithmTags.SHA1); + // Build key encrypter and decrypter based on passphrase + PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( + PGPEncryptedData.CAST5, sha1Calc) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray()); + PGPSecretKey masterSecretKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(), + sha1Calc, true, keyEncryptor); + PGPSecretKeyRing sKR = new PGPSecretKeyRing( masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator()); - return internal(sKR, masterSecretKey, saveParcel, saveParcel.newPassphrase, log, indent); + return internal(sKR, masterSecretKey, saveParcel, "", log, indent); } catch (PGPException e) { Log.e(Constants.TAG, "pgp error encoding key", e); @@ -207,6 +202,7 @@ public class PgpKeyOperation { Log.e(Constants.TAG, "io error encoding key", e); return null; } catch (PgpGeneralMsgIdException e) { + Log.e(Constants.TAG, "pgp msg id error", e); return null; } @@ -374,16 +370,36 @@ public class PgpKeyOperation { } log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent); - PGPSecretKey sKey = createKey(add.mAlgorithm, add.mKeysize, passphrase, false); + + // generate a new secret key (privkey only for now) + PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize); + + // add subkey binding signature (making this a sub rather than master key) + PGPPublicKey pKey = keyPair.getPublicKey(); + PGPSignature cert = generateSubkeyBindingSignature( + masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey, + add.mFlags, add.mExpiry); + pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert); + + PGPSecretKey sKey; { + // define hashing and signing algos + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder() + .build().get(HashAlgorithmTags.SHA1); + + // Build key encrypter and decrypter based on passphrase + PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( + PGPEncryptedData.CAST5, sha1Calc) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray()); + + sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey, + sha1Calc, false, keyEncryptor); + } + log.add(LogLevel.DEBUG, LogType.MSG_MF_SUBKEY_NEW_ID, indent+1, PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID())); - PGPPublicKey pKey = sKey.getPublicKey(); - PGPSignature cert = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, - sKey, pKey, add.mFlags, add.mExpiry, passphrase); - pKey = PGPPublicKey.addCertification(pKey, cert); - sKey = PGPSecretKey.replacePublicKey(sKey, pKey); - sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey)); + sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey); + } catch (PgpGeneralMsgIdException e) { return null; } @@ -478,6 +494,18 @@ public class PgpKeyOperation { PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPSecretKey sKey, PGPPublicKey pKey, int flags, Long expiry, String passphrase) throws IOException, PGPException, SignatureException { + PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( + passphrase.toCharArray()); + PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor); + return generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, subPrivateKey, + pKey, flags, expiry); + } + + private static PGPSignature generateSubkeyBindingSignature( + PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, + PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, Long expiry) + throws IOException, PGPException, SignatureException { // date for signing Date todayDate = new Date(); @@ -485,12 +513,6 @@ public class PgpKeyOperation { // If this key can sign, we need a primary key binding signature if ((flags & KeyFlags.SIGN_DATA) != 0) { - - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - passphrase.toCharArray()); - PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor); - // cross-certify signing keys PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator(); subHashedPacketsGen.setSignatureCreationTime(false, todayDate); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java index d5d02081a..755827482 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -27,8 +27,10 @@ import android.support.v4.app.FragmentManager; import com.devspark.appmsg.AppMsg; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; +import org.sufficientlysecure.keychain.util.Log; public class KeychainIntentServiceHandler extends Handler { @@ -126,6 +128,7 @@ public class KeychainIntentServiceHandler extends Handler { break; default: + Log.e(Constants.TAG, "unknown handler message!"); break; } } -- cgit v1.2.3 From 6f558add35c7c68a6b28a638dadfff75838ef9ba Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 2 Jul 2014 15:05:02 +0200 Subject: use expert create key for key creation testing (revert this later on!) --- .../keychain/ui/KeyListActivity.java | 55 ++++++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java index 7ce7a06aa..849576284 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -17,21 +17,33 @@ package org.sufficientlysecure.keychain.ui; +import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; import android.view.Menu; import android.view.MenuItem; import com.devspark.appmsg.AppMsg; +import org.spongycastle.bcpg.sig.KeyFlags; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.Constants.choice.algorithm; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.ExportHelper; +import org.sufficientlysecure.keychain.helper.OtherHelper; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainDatabase; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd; import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; +import java.util.ArrayList; public class KeyListActivity extends DrawerActivity { @@ -121,9 +133,42 @@ public class KeyListActivity extends DrawerActivity { } private void createKeyExpert() { - Intent intent = new Intent(this, EditKeyActivity.class); - intent.setAction(EditKeyActivity.ACTION_CREATE_KEY); - startActivityForResult(intent, 0); + Intent intent = new Intent(this, KeychainIntentService.class); + intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING); + + // Message is received after importing is done in KeychainIntentService + KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( + this, + getString(R.string.progress_importing), + ProgressDialog.STYLE_HORIZONTAL) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + Bundle data = message.getData(); + // OtherHelper.logDebugBundle(data, "message reply"); + } + }; + + // fill values for this action + Bundle data = new Bundle(); + + SaveKeyringParcel parcel = new SaveKeyringParcel(); + parcel.addSubKeys.add(new SubkeyAdd(algorithm.rsa, 1024, KeyFlags.CERTIFY_OTHER, null)); + parcel.addSubKeys.add(new SubkeyAdd(algorithm.rsa, 1024, KeyFlags.SIGN_DATA, null)); + parcel.addUserIds.add("swagerinho"); + parcel.newPassphrase = "swag"; + + // get selected key entries + data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, parcel); + + 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(this); + + startService(intent); } - -} +} \ No newline at end of file -- cgit v1.2.3 From 4f83a4f1636e674bea60d806610f55022c2d9b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 2 Jul 2014 15:10:50 +0200 Subject: Edit key: adding user ids --- .../keychain/service/PassphraseCacheService.java | 31 ++-- .../keychain/ui/EditKeyActivity.java | 2 +- .../keychain/ui/EditKeyFragment.java | 47 ++--- .../keychain/ui/KeyListFragment.java | 14 -- .../keychain/ui/LoaderFragment.java | 24 ++- .../keychain/ui/adapter/UserIdsAdapter.java | 3 + .../keychain/ui/adapter/UserIdsAddedAdapter.java | 206 +++++++++++++++++++++ .../keychain/ui/adapter/UserIdsNewAdapter.java | 146 --------------- .../keychain/ui/widget/FixedListView.java | 4 +- .../keychain/ui/widget/SectionView.java | 2 +- .../src/main/res/layout/edit_key_fragment.xml | 2 +- .../res/layout/edit_key_user_id_added_item.xml | 59 ++++++ OpenKeychain/src/main/res/layout/key_list_item.xml | 13 -- .../src/main/res/layout/view_key_userids_item.xml | 13 +- 14 files changed, 330 insertions(+), 236 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsNewAdapter.java create mode 100644 OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index d42bae67a..28f230f71 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -49,7 +49,6 @@ import java.util.Date; * convenience. */ public class PassphraseCacheService extends Service { - public static final String TAG = Constants.TAG + ": PassphraseCacheService"; public static final String ACTION_PASSPHRASE_CACHE_ADD = Constants.INTENT_PREFIX + "PASSPHRASE_CACHE_ADD"; @@ -83,7 +82,7 @@ public class PassphraseCacheService extends Service { * @param passphrase */ public static void addCachedPassphrase(Context context, long keyId, String passphrase) { - Log.d(TAG, "cacheNewPassphrase() for " + keyId); + Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + keyId); Intent intent = new Intent(context, PassphraseCacheService.class); intent.setAction(ACTION_PASSPHRASE_CACHE_ADD); @@ -103,7 +102,7 @@ public class PassphraseCacheService extends Service { * @return passphrase or null (if no passphrase is cached for this keyId) */ public static String getCachedPassphrase(Context context, long keyId) { - Log.d(TAG, "getCachedPassphrase() get masterKeyId for " + keyId); + Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphrase() get masterKeyId for " + keyId); Intent intent = new Intent(context, PassphraseCacheService.class); intent.setAction(ACTION_PASSPHRASE_CACHE_GET); @@ -159,7 +158,7 @@ public class PassphraseCacheService extends Service { private String getCachedPassphraseImpl(long keyId) { // passphrase for symmetric encryption? if (keyId == Constants.key.symmetric) { - Log.d(TAG, "getCachedPassphraseImpl() for symmetric encryption"); + Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption"); String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric); if (cachedPassphrase == null) { return null; @@ -170,7 +169,7 @@ public class PassphraseCacheService extends Service { // try to get master key id which is used as an identifier for cached passphrases try { - Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + keyId); + Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for masterKeyId " + keyId); WrappedSecretKeyRing key = new ProviderHelper(this).getWrappedSecretKeyRing( KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(keyId)); // no passphrase needed? just add empty string and return it, then @@ -184,18 +183,18 @@ public class PassphraseCacheService extends Service { // get cached passphrase String cachedPassphrase = mPassphraseCache.get(keyId); if (cachedPassphrase == null) { - Log.d(TAG, "Passphrase not (yet) cached, returning null"); + Log.d(Constants.TAG, "PassphraseCacheService Passphrase not (yet) cached, returning null"); // not really an error, just means the passphrase is not cached but not empty either return null; } // set it again to reset the cache life cycle - Log.d(TAG, "Cache passphrase again when getting it!"); + Log.d(Constants.TAG, "PassphraseCacheService Cache passphrase again when getting it!"); addCachedPassphrase(this, keyId, cachedPassphrase); return cachedPassphrase; } catch (ProviderHelper.NotFoundException e) { - Log.e(TAG, "Passphrase for unknown key was requested!"); + Log.e(Constants.TAG, "PassphraseCacheService Passphrase for unknown key was requested!"); return null; } } @@ -212,7 +211,7 @@ public class PassphraseCacheService extends Service { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - Log.d(TAG, "Received broadcast..."); + Log.d(Constants.TAG, "PassphraseCacheService Received broadcast..."); if (action.equals(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE)) { long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1); @@ -248,7 +247,7 @@ public class PassphraseCacheService extends Service { */ @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(TAG, "onStartCommand()"); + Log.d(Constants.TAG, "PassphraseCacheService.onStartCommand()"); // register broadcastreceiver registerReceiver(); @@ -259,8 +258,8 @@ public class PassphraseCacheService extends Service { long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1); String passphrase = intent.getStringExtra(EXTRA_PASSPHRASE); - Log.d(TAG, - "Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with keyId: " + Log.d(Constants.TAG, + "PassphraseCacheService Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with keyId: " + keyId + ", ttl: " + ttl); // add keyId and passphrase to memory @@ -285,10 +284,10 @@ public class PassphraseCacheService extends Service { try { messenger.send(msg); } catch (RemoteException e) { - Log.e(Constants.TAG, "Sending message failed", e); + Log.e(Constants.TAG, "PassphraseCacheService Sending message failed", e); } } else { - Log.e(Constants.TAG, "Intent or Intent Action not supported!"); + Log.e(Constants.TAG, "PassphraseCacheService Intent or Intent Action not supported!"); } } @@ -305,11 +304,11 @@ public class PassphraseCacheService extends Service { // remove passphrase corresponding to keyId from memory mPassphraseCache.remove(keyId); - Log.d(TAG, "Timeout of keyId " + keyId + ", removed from memory!"); + Log.d(Constants.TAG, "PassphraseCacheService Timeout of keyId " + keyId + ", removed from memory!"); // stop whole service if no cached passphrases remaining if (mPassphraseCache.size() == 0) { - Log.d(TAG, "No passphrases remaining in memory, stopping service!"); + Log.d(Constants.TAG, "PassphraseCacheServic No passphrases remaining in memory, stopping service!"); stopSelf(); } } 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 d734c31db..906ed347e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -231,7 +231,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { // get new key from data bundle returned from service - Bundle data = message.getData(); + Bundle data = message.getDataAsStringList(); ArrayList newKeys = PgpConversionHelper.BytesToPGPSecretKeyList(data 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 079263e64..ccb525c05 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -51,13 +51,14 @@ import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; -import org.sufficientlysecure.keychain.ui.adapter.UserIdsNewAdapter; -import org.sufficientlysecure.keychain.ui.dialog.AddUserIdDialogFragment; +import org.sufficientlysecure.keychain.ui.adapter.UserIdsAddedAdapter; import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; import org.sufficientlysecure.keychain.util.Log; +import java.util.ArrayList; + public class EditKeyFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks { @@ -76,7 +77,8 @@ public class EditKeyFragment extends LoaderFragment implements private UserIdsAdapter mUserIdsAdapter; private SubkeysAdapter mKeysAdapter; - private UserIdsNewAdapter mUserIdsAddedAdapter; + private UserIdsAddedAdapter mUserIdsAddedAdapter; + private ArrayList mUserIdsAddedData; private Uri mDataUri; @@ -189,9 +191,10 @@ public class EditKeyFragment extends LoaderFragment implements } }); - mUserIdsAddedAdapter = new UserIdsNewAdapter(getActivity()); + // TODO: from savedInstance?! + mUserIdsAddedData = new ArrayList(); + mUserIdsAddedAdapter = new UserIdsAddedAdapter(getActivity(), mUserIdsAddedData); mUserIdsAddedList.setAdapter(mUserIdsAddedAdapter); - mUserIdsAddedAdapter.setData(mSaveKeyringParcel.addUserIds); mKeysAdapter = new SubkeysAdapter(getActivity(), null, 0); mKeysList.setAdapter(mKeysAdapter); @@ -321,40 +324,12 @@ public class EditKeyFragment extends LoaderFragment implements } private void addUserId() { -// mSaveKeyringParcel.addUserIds.add(userId); -// mUserIdsAddedAdapter.setData(mSaveKeyringParcel.addUserIds); - - -// Handler returnHandler = new Handler() { -// @Override -// public void handleMessage(Message message) { -// switch (message.what) { -// case AddUserIdDialogFragment.MESSAGE_OKAY: -// Bundle data = message.getData(); -// String userId = data.getString(AddUserIdDialogFragment.MESSAGE_DATA_USER_ID); -// -// if (userId != null) { - -// } -// } -// getLoaderManager().getLoader(LOADER_ID_USER_IDS).forceLoad(); -// } -// }; -// -// // Create a new Messenger for the communication back -// final Messenger messenger = new Messenger(returnHandler); -// -// DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { -// public void run() { -// AddUserIdDialogFragment dialogFragment = -// AddUserIdDialogFragment.newInstance(messenger); -// -// dialogFragment.show(getActivity().getSupportFragmentManager(), "addUserIdDialog"); -// } -// }); + mUserIdsAddedAdapter.add(new UserIdsAddedAdapter.UserIdModel()); } private void save() { + Log.d(Constants.TAG, "data: " + mUserIdsAddedAdapter.getDataAsStringList()); + String passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), mSaveKeyringParcel.mMasterKeyId); if (passphrase == null) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index d2cb5283d..68ac6d30c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -441,7 +441,6 @@ public class KeyListFragment extends LoaderFragment TextView mMainUserIdRest; View mStatusDivider; FrameLayout mStatusLayout; - ImageButton mButton; TextView mRevoked; ImageView mVerified; } @@ -454,7 +453,6 @@ public class KeyListFragment extends LoaderFragment holder.mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); holder.mStatusDivider = (View) view.findViewById(R.id.status_divider); holder.mStatusLayout = (FrameLayout) view.findViewById(R.id.status_layout); - holder.mButton = (ImageButton) view.findViewById(R.id.edit); holder.mRevoked = (TextView) view.findViewById(R.id.revoked); holder.mVerified = (ImageView) view.findViewById(R.id.verified); view.setTag(holder); @@ -496,21 +494,9 @@ public class KeyListFragment extends LoaderFragment h.mStatusLayout.setVisibility(View.VISIBLE); h.mRevoked.setVisibility(View.GONE); h.mVerified.setVisibility(View.GONE); - h.mButton.setVisibility(View.VISIBLE); - - final long id = cursor.getLong(INDEX_MASTER_KEY_ID); - h.mButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); - editIntent.setData(KeyRingData.buildSecretKeyRingUri(Long.toString(id))); - editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY); - startActivityForResult(editIntent, 0); - } - }); } else { // this is a public key - hide the edit mButton, show if it's revoked h.mStatusDivider.setVisibility(View.GONE); - h.mButton.setVisibility(View.GONE); boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0; boolean isExpired = !cursor.isNull(INDEX_EXPIRY) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java index 87ab1bb8c..8634070cc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java @@ -1,3 +1,20 @@ +/* + * 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.os.Bundle; @@ -9,14 +26,14 @@ import android.view.animation.AnimationUtils; import org.sufficientlysecure.keychain.R; -/** This is a fragment helper class, which implements a generic +/** + * This is a fragment helper class, which implements a generic * progressbar/container view. - * + *

* To use it in a fragment, simply subclass, use onCreateView to create the * layout's root view, and ues getContainer() as root view of your subclass. * The layout shows a progress bar by default, and can be switched to the * actual contents by calling setContentShown(). - * */ public class LoaderFragment extends Fragment { private boolean mContentShown; @@ -35,7 +52,6 @@ public class LoaderFragment extends Fragment { mContentShown = false; return root; - } protected ViewGroup getContainer() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index 7fc78dc41..7bf9334b8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -123,6 +123,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC TextView vComment = (TextView) view.findViewById(R.id.comment); ImageView vVerified = (ImageView) view.findViewById(R.id.certified); ImageView vHasChanges = (ImageView) view.findViewById(R.id.has_changes); + ImageView vEditImage = (ImageView) view.findViewById(R.id.edit_image); String userId = cursor.getString(mIndexUserId); String[] splitUserId = KeyRing.splitUserId(userId); @@ -167,8 +168,10 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC } else { vHasChanges.setVisibility(View.GONE); } + vEditImage.setVisibility(View.VISIBLE); } else { vHasChanges.setVisibility(View.GONE); + vEditImage.setVisibility(View.GONE); } if (isRevoked) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java new file mode 100644 index 000000000..ff0ec70f3 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java @@ -0,0 +1,206 @@ +/* + * 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.adapter; + +import android.app.Activity; +import android.content.Context; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.Patterns; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.EditText; +import android.widget.ImageButton; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.ContactHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; + +public class UserIdsAddedAdapter extends ArrayAdapter { + private LayoutInflater mInflater; + private Activity mActivity; + + private ArrayAdapter mAutoCompleteNameAdapter; + private ArrayAdapter mAutoCompleteEmailAdapter; + + // hold a private reference to the underlying data List + private List mData; + + public static class UserIdModel { + String name = ""; + String address = ""; + String comment = ""; + + @Override + public String toString() { + String userId = null; + if (!TextUtils.isEmpty(name)) { + userId = name; + if (!TextUtils.isEmpty(comment)) { + userId += " (" + comment + ")"; + } + if (!TextUtils.isEmpty(address)) { + userId += " <" + address + ">"; + } + } + return userId; + } + } + + public UserIdsAddedAdapter(Activity activity, List data) { + super(activity, -1, data); + mActivity = activity; + mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mData = data; + mAutoCompleteNameAdapter = new ArrayAdapter + (mActivity, android.R.layout.simple_dropdown_item_1line, + ContactHelper.getPossibleUserNames(mActivity) + ); + mAutoCompleteEmailAdapter = new ArrayAdapter + (mActivity, android.R.layout.simple_dropdown_item_1line, + ContactHelper.getPossibleUserEmails(mActivity) + ); + } + + public List getDataAsStringList() { + ArrayList out = new ArrayList(); + for (UserIdModel id : mData) { + out.add(id.toString()); + } + + return out; + } + + static class ViewHolder { + public AutoCompleteTextView vAddress; + public AutoCompleteTextView vName; + public EditText vComment; + public ImageButton vDelete; + // also hold a reference to the model item + public UserIdModel mModel; + } + + public View getView(final int position, View convertView, ViewGroup parent) { + if (convertView == null) { + // Not recycled, inflate a new view + convertView = mInflater.inflate(R.layout.edit_key_user_id_added_item, null); + final ViewHolder viewHolder = new ViewHolder(); + viewHolder.vAddress = (AutoCompleteTextView) convertView.findViewById(R.id.user_id_added_item_address); + viewHolder.vName = (AutoCompleteTextView) convertView.findViewById(R.id.user_id_added_item_name); + viewHolder.vComment = (EditText) convertView.findViewById(R.id.user_id_added_item_comment); + viewHolder.vDelete = (ImageButton) convertView.findViewById(R.id.user_id_added_item_delete); + convertView.setTag(viewHolder); + + viewHolder.vAddress.addTextChangedListener(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 referenced item in view holder + viewHolder.mModel.address = s.toString(); + + // show icon on valid email addresses + if (viewHolder.mModel.address.length() > 0) { + Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(viewHolder.mModel.address); + if (emailMatcher.matches()) { + viewHolder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.uid_mail_ok, 0); + } else { + viewHolder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.uid_mail_bad, 0); + } + } else { + // remove drawable if email is empty + viewHolder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + } + } + }); + + viewHolder.vName.addTextChangedListener(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 referenced item in view holder + viewHolder.mModel.name = s.toString(); + } + }); + + viewHolder.vComment.addTextChangedListener(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 referenced item in view holder + viewHolder.mModel.comment = s.toString(); + } + }); + + viewHolder.vDelete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // remove reference model item from adapter (data and notify about change) + UserIdsAddedAdapter.this.remove(viewHolder.mModel); + } + }); + + } + final ViewHolder holder = (ViewHolder) convertView.getTag(); + + // save reference to model item + holder.mModel = getItem(position); + + holder.vAddress.setText(holder.mModel.address); + holder.vAddress.setThreshold(1); // Start working from first character + holder.vAddress.setAdapter(mAutoCompleteEmailAdapter); + + holder.vName.setText(holder.mModel.name); + holder.vName.setThreshold(1); // Start working from first character + holder.vName.setAdapter(mAutoCompleteNameAdapter); + + holder.vComment.setText(holder.mModel.comment); + + return convertView; + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsNewAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsNewAdapter.java deleted file mode 100644 index dffce50a4..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsNewAdapter.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2013-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.adapter; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Context; -import android.os.Build; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.KeyRing; - -import java.util.List; - -public class UserIdsNewAdapter extends ArrayAdapter { - protected LayoutInflater mInflater; - protected Activity mActivity; - - protected List mData; - -// static class ViewHolder { -// public TextView vName; -// public TextView vAddress; -// public TextView vComment; -// public ImageView vVerified; -// public ImageView vHasChanges; -// public CheckBox vCheckBox; -// } - - public UserIdsNewAdapter(Activity activity) { - super(activity, -1); - mActivity = activity; - mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public void setData(List data) { - clear(); - if (data != null) { - this.mData = data; - - // add data to extended ArrayAdapter - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - addAll(data); - } else { - for (String entry : data) { - add(entry); - } - } - } - } - - public List getData() { -// String name = mName.getText().toString(); -// - String email = mAddress.getText().toString(); -// - String comment = mComment.getText().toString(); -// - -// - String userId = null; -// - if (!TextUtils.isEmpty(name)) { -// - userId = name; -// - if (!TextUtils.isEmpty(comment)) { -// - userId += " (" + comment + ")"; -// - } -// - if (!TextUtils.isEmpty(email)) { -// - userId += " <" + email + ">"; -// - } -// - } - return mData; - } - - @Override - public boolean hasStableIds() { - return true; - } - - public View getView(int position, View convertView, ViewGroup parent) { - String entry = mData.get(position); -// ViewHolder holder; -// if (convertView == null) { -// holder = new ViewHolder(); - convertView = mInflater.inflate(R.layout.edit_key_new_userids_item, null); - EditText vName = (EditText) convertView.findViewById(R.id.userId); - EditText vAddress = (EditText) convertView.findViewById(R.id.address); - EditText vComment = (EditText) convertView.findViewById(R.id.comment); -// holder.vVerified = (ImageView) convertView.findViewById(R.id.certified); - ImageView vHasChanges = (ImageView) convertView.findViewById(R.id.has_changes); -// holder.vCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox); -// convertView.setTag(holder); -// } else { -// holder = (ViewHolder) convertView.getTag(); -// } - -// // user id -// String[] splitUserId = KeyRing.splitUserId(entry); -// if (splitUserId[0] != null) { -// vName.setText(splitUserId[0]); -// } else { -// vName.setText(R.string.user_id_no_name); -// } -// if (splitUserId[1] != null) { -// vAddress.setText(splitUserId[1]); -// vAddress.setVisibility(View.VISIBLE); -// } else { -// holder.vAddress.setVisibility(View.GONE); -// } -// if (splitUserId[2] != null) { -// vComment.setText(splitUserId[2]); -// vComment.setVisibility(View.VISIBLE); -// } else { -// holder.vComment.setVisibility(View.GONE); -// } -// -// holder.vCheckBox.setVisibility(View.GONE); -// -// holder.vVerified.setImageResource(R.drawable.key_certify_ok_depth0); -// -// // all items are "new" -// holder.vHasChanges.setVisibility(View.VISIBLE); - - return convertView; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java index da29f808a..294ff1500 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java @@ -25,9 +25,7 @@ import android.widget.ListView; * Automatically calculate height of ListView based on contained items. This enables to put this * ListView into a ScrollView without messing up. *

- * from - * http://stackoverflow.com/questions/2419246/how-do-i-create-a-listview-thats-not-in-a-scrollview- - * or-has-the-scrollview-dis + * from http://stackoverflow.com/a/3580117 */ public class FixedListView extends ListView { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java index 4ecc96cee..cd5671801 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -388,7 +388,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { // get new key from data bundle returned from service - Bundle data = message.getData(); + Bundle data = message.getDataAsStringList(); UncachedSecretKey newKey = PgpConversionHelper .BytesToPGPSecretKey(data .getByteArray(KeychainIntentService.RESULT_NEW_KEY)); diff --git a/OpenKeychain/src/main/res/layout/edit_key_fragment.xml b/OpenKeychain/src/main/res/layout/edit_key_fragment.xml index 7f94cb3cd..05e6c09c5 100644 --- a/OpenKeychain/src/main/res/layout/edit_key_fragment.xml +++ b/OpenKeychain/src/main/res/layout/edit_key_fragment.xml @@ -111,7 +111,7 @@ android:layout_height="match_parent" android:text="add key" android:minHeight="?android:attr/listPreferredItemHeight" - android:drawableRight="@drawable/ic_action_add_person" + android:drawableRight="@drawable/ic_action_new_account" android:drawablePadding="8dp" android:gravity="center_vertical" android:clickable="true" diff --git a/OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml b/OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml new file mode 100644 index 000000000..542c59b12 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/edit_key_user_id_added_item.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + diff --git a/OpenKeychain/src/main/res/layout/key_list_item.xml b/OpenKeychain/src/main/res/layout/key_list_item.xml index 73a20bd2e..86b2c320d 100644 --- a/OpenKeychain/src/main/res/layout/key_list_item.xml +++ b/OpenKeychain/src/main/res/layout/key_list_item.xml @@ -51,19 +51,6 @@ android:layout_width="wrap_content" android:layout_height="match_parent"> - - + android:background="@color/result_green" /> @@ -68,4 +70,13 @@ + + + -- cgit v1.2.3 From 3d34eb8ca44c03b74577158b82460b7e1842e35b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 2 Jul 2014 15:42:38 +0200 Subject: edit key: work on saving --- .../keychain/ui/EditKeyFragment.java | 17 +++++++++++------ .../keychain/ui/KeyListFragment.java | 8 ++------ .../keychain/ui/adapter/UserIdsAddedAdapter.java | 22 +++++++++++----------- OpenKeychain/src/main/res/layout/key_list_item.xml | 8 -------- 4 files changed, 24 insertions(+), 31 deletions(-) (limited to 'OpenKeychain/src') 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 ccb525c05..1defa4034 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -328,8 +328,6 @@ public class EditKeyFragment extends LoaderFragment implements } private void save() { - Log.d(Constants.TAG, "data: " + mUserIdsAddedAdapter.getDataAsStringList()); - String passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), mSaveKeyringParcel.mMasterKeyId); if (passphrase == null) { @@ -338,17 +336,23 @@ public class EditKeyFragment extends LoaderFragment implements @Override public void handleMessage(Message message) { if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - saveFinal(); + String passphrase = + message.getData().getString(PassphraseDialogFragment.MESSAGE_DATA_PASSPHRASE); + Log.d(Constants.TAG, "after caching passphrase"); + saveFinal(passphrase); } } } ); - + } else { + saveFinal(passphrase); } - } - private void saveFinal() { + private void saveFinal(String passphrase) { + Log.d(Constants.TAG, "add userids to parcel: " + mUserIdsAddedAdapter.getDataAsStringList()); + mSaveKeyringParcel.addUserIds = mUserIdsAddedAdapter.getDataAsStringList(); + // Message is received after importing is done in KeychainIntentService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( getActivity(), @@ -386,6 +390,7 @@ public class EditKeyFragment extends LoaderFragment implements // fill values for this action Bundle data = new Bundle(); + data.putString(KeychainIntentService.SAVE_KEYRING_PASSPHRASE, passphrase); data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, mSaveKeyringParcel); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 68ac6d30c..d6b0c7944 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -439,7 +439,6 @@ public class KeyListFragment extends LoaderFragment private class ItemViewHolder { TextView mMainUserId; TextView mMainUserIdRest; - View mStatusDivider; FrameLayout mStatusLayout; TextView mRevoked; ImageView mVerified; @@ -451,7 +450,6 @@ public class KeyListFragment extends LoaderFragment ItemViewHolder holder = new ItemViewHolder(); holder.mMainUserId = (TextView) view.findViewById(R.id.mainUserId); holder.mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - holder.mStatusDivider = (View) view.findViewById(R.id.status_divider); holder.mStatusLayout = (FrameLayout) view.findViewById(R.id.status_layout); holder.mRevoked = (TextView) view.findViewById(R.id.revoked); holder.mVerified = (ImageView) view.findViewById(R.id.verified); @@ -489,14 +487,12 @@ public class KeyListFragment extends LoaderFragment { // set edit button and revoked info, specific by key type if (cursor.getInt(KeyListFragment.INDEX_HAS_ANY_SECRET) != 0) { - // this is a secret key - show the edit mButton - h.mStatusDivider.setVisibility(View.VISIBLE); + // this is a secret key h.mStatusLayout.setVisibility(View.VISIBLE); h.mRevoked.setVisibility(View.GONE); h.mVerified.setVisibility(View.GONE); } else { - // this is a public key - hide the edit mButton, show if it's revoked - h.mStatusDivider.setVisibility(View.GONE); + // this is a public key - show if it's revoked boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0; boolean isExpired = !cursor.isNull(INDEX_EXPIRY) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java index ff0ec70f3..137217ff4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java @@ -55,15 +55,12 @@ public class UserIdsAddedAdapter extends ArrayAdapter"; - } + String userId = name; + if (!TextUtils.isEmpty(comment)) { + userId += " (" + comment + ")"; + } + if (!TextUtils.isEmpty(address)) { + userId += " <" + address + ">"; } return userId; } @@ -84,10 +81,13 @@ public class UserIdsAddedAdapter extends ArrayAdapter getDataAsStringList() { + public ArrayList getDataAsStringList() { ArrayList out = new ArrayList(); for (UserIdModel id : mData) { - out.add(id.toString()); + // ignore empty user ids + if (!TextUtils.isEmpty(id.toString())) { + out.add(id.toString()); + } } return out; diff --git a/OpenKeychain/src/main/res/layout/key_list_item.xml b/OpenKeychain/src/main/res/layout/key_list_item.xml index 86b2c320d..99e4c0268 100644 --- a/OpenKeychain/src/main/res/layout/key_list_item.xml +++ b/OpenKeychain/src/main/res/layout/key_list_item.xml @@ -38,14 +38,6 @@ android:textAppearance="?android:attr/textAppearanceSmall" /> - - Date: Wed, 2 Jul 2014 16:02:56 +0200 Subject: support changing primary user id in SaveKeyringParcel Closes #695 --- .../keychain/pgp/PgpKeyOperation.java | 115 ++++++++++++++++++++- .../keychain/service/OperationResultParcel.java | 2 + OpenKeychain/src/main/res/values/strings.xml | 2 + 3 files changed, 115 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 528d36da2..9a08290e4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -52,6 +52,7 @@ import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType; import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd; +import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Primes; @@ -66,6 +67,7 @@ import java.security.SignatureException; import java.util.Arrays; import java.util.Calendar; import java.util.Date; +import java.util.Iterator; import java.util.TimeZone; /** @@ -289,14 +291,42 @@ public class PgpKeyOperation { // 2a. Add certificates for new user ids for (String userId : saveParcel.addUserIds) { log.add(LogLevel.INFO, LogType.MSG_MF_UID_ADD, indent); + + // this operation supersedes all previous binding and revocation certificates, + // so remove those to retain assertions from canonicalization for later operations + @SuppressWarnings("unchecked") + Iterator it = modifiedPublicKey.getSignaturesForID(userId); + if (it != null) { + for (PGPSignature cert : new IterableIterator(it)) { + // if it's not a self cert, never mind + if (cert.getKeyID() != masterPublicKey.getKeyID()) { + continue; + } + if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION + || cert.getSignatureType() == PGPSignature.NO_CERTIFICATION + || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION + || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION + || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) { + modifiedPublicKey = PGPPublicKey.removeCertification( + modifiedPublicKey, userId, cert); + } + } + } + + // if it's supposed to be primary, we can do that here as well + boolean isPrimary = saveParcel.changePrimaryUserId != null + && userId.equals(saveParcel.changePrimaryUserId); + // generate and add new certificate PGPSignature cert = generateUserIdSignature(masterPrivateKey, - masterPublicKey, userId, false); + masterPublicKey, userId, isPrimary); modifiedPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, cert); } // 2b. Add revocations for revoked user ids for (String userId : saveParcel.revokeUserIds) { log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent); + // a duplicate revocatin will be removed during canonicalization, so no need to + // take care of that here. PGPSignature cert = generateRevocationSignature(masterPrivateKey, masterPublicKey, userId); modifiedPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, cert); @@ -305,7 +335,84 @@ public class PgpKeyOperation { // 3. If primary user id changed, generate new certificates for both old and new if (saveParcel.changePrimaryUserId != null) { log.add(LogLevel.INFO, LogType.MSG_MF_UID_PRIMARY, indent); - // todo + + // we work on the modifiedPublicKey here, to respect new or newly revoked uids + // noinspection unchecked + for (String userId : new IterableIterator(modifiedPublicKey.getUserIDs())) { + boolean isRevoked = false; + PGPSignature currentCert = null; + // noinspection unchecked + for (PGPSignature cert : new IterableIterator( + masterPublicKey.getSignaturesForID(userId))) { + // if it's not a self cert, never mind + if (cert.getKeyID() != masterPublicKey.getKeyID()) { + continue; + } + // we know from canonicalization that if there is any revocation here, it + // is valid and not superseded by a newer certification. + if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) { + isRevoked = true; + continue; + } + // we know from canonicalization that there is only one binding + // certification here, so we can just work with the first one. + if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION || + cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION || + cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION || + cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) { + currentCert = cert; + } + } + + if (currentCert == null) { + // no certificate found?! error error error + log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent); + return null; + } + + // we definitely should not update certifications of revoked keys, so just leave it. + if (isRevoked) { + // revoked user ids cannot be primary! + if (userId.equals(saveParcel.changePrimaryUserId)) { + log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent); + return null; + } + continue; + } + + // if this is~ the/a primary user id + if (currentCert.hasSubpackets() && currentCert.getHashedSubPackets().isPrimaryUserID()) { + // if it's the one we want, just leave it as is + if (userId.equals(saveParcel.changePrimaryUserId)) { + continue; + } + // otherwise, generate new non-primary certification + modifiedPublicKey = PGPPublicKey.removeCertification( + modifiedPublicKey, userId, currentCert); + PGPSignature newCert = generateUserIdSignature( + masterPrivateKey, masterPublicKey, userId, false); + modifiedPublicKey = PGPPublicKey.addCertification( + modifiedPublicKey, userId, newCert); + continue; + } + + // if we are here, this is not currently a primary user id + + // if it should be + if (userId.equals(saveParcel.changePrimaryUserId)) { + // add shiny new primary user id certificate + modifiedPublicKey = PGPPublicKey.removeCertification( + modifiedPublicKey, userId, currentCert); + PGPSignature newCert = generateUserIdSignature( + masterPrivateKey, masterPublicKey, userId, true); + modifiedPublicKey = PGPPublicKey.addCertification( + modifiedPublicKey, userId, newCert); + } + + // user id is not primary and is not supposed to be - nothing to do here. + + } + } // Update the secret key ring @@ -315,7 +422,6 @@ public class PgpKeyOperation { sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey); } - // 4a. For each subkey change, generate new subkey binding certificate for (SaveKeyringParcel.SubkeyChange change : saveParcel.changeSubKeys) { log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_CHANGE, @@ -334,7 +440,8 @@ public class PgpKeyOperation { return null; } - // generate and add new signature + // generate and add new signature. we can be sloppy here and just leave the old one, + // it will be removed during canonicalization PGPSignature sig = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, sKey, pKey, change.mFlags, change.mExpiry, passphrase); pKey = PGPPublicKey.addCertification(pKey, sig); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java index 535fa08cf..f5d5b8f97 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java @@ -241,6 +241,8 @@ public class OperationResultParcel implements Parcelable { MSG_MF_ERROR_ENCODE (R.string.msg_mf_error_encode), MSG_MF_ERROR_FINGERPRINT (R.string.msg_mf_error_fingerprint), MSG_MF_ERROR_KEYID (R.string.msg_mf_error_keyid), + MSG_MF_ERROR_INTEGRITY (R.string.msg_mf_error_integrity), + MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary), MSG_MF_ERROR_PGP (R.string.msg_mf_error_pgp), MSG_MF_ERROR_SIG (R.string.msg_mf_error_sig), MSG_MF_PASSPHRASE (R.string.msg_mf_passphrase), diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index d886fe241..d91707567 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -628,6 +628,8 @@ Encoding exception! Actual key fingerprint does not match expected! No keyid. This is a programming error, please file a bug report! + Internal error, integrity check failed! + Revoked user ids cannot be primary! PGP internal exception! Signature exception! Changing passphrase -- cgit v1.2.3 From 94a58f3aa8e202b1a7d5587aeeb85b13a99d4895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 2 Jul 2014 16:33:30 +0200 Subject: remove init methods from adapter --- .../keychain/service/KeychainIntentService.java | 1 + .../keychain/ui/EditKeyFragment.java | 16 ++--- .../keychain/ui/adapter/SubkeysAdapter.java | 81 ++++++++-------------- .../keychain/ui/adapter/UserIdsAdapter.java | 43 ++++-------- 4 files changed, 53 insertions(+), 88 deletions(-) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index e1514b16f..48119a831 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -343,6 +343,7 @@ public class KeychainIntentService extends IntentService setProgress(R.string.progress_done, 100, 100); + // cache new passphrase if (saveParcel.newPassphrase != null) { PassphraseCacheService.addCachedPassphrase(this, masterKeyId, saveParcel.newPassphrase); } 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 1defa4034..8c7606cf9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -65,7 +65,7 @@ public class EditKeyFragment extends LoaderFragment implements public static final String ARG_DATA_URI = "uri"; private ListView mUserIdsList; - private ListView mKeysList; + private ListView mSubkeysList; private ListView mUserIdsAddedList; private ListView mKeysAddedList; private View mChangePassphrase; @@ -76,7 +76,7 @@ public class EditKeyFragment extends LoaderFragment implements private static final int LOADER_ID_KEYS = 1; private UserIdsAdapter mUserIdsAdapter; - private SubkeysAdapter mKeysAdapter; + private SubkeysAdapter mSubkeysAdapter; private UserIdsAddedAdapter mUserIdsAddedAdapter; private ArrayList mUserIdsAddedData; @@ -104,7 +104,7 @@ public class EditKeyFragment extends LoaderFragment implements View view = inflater.inflate(R.layout.edit_key_fragment, getContainer()); mUserIdsList = (ListView) view.findViewById(R.id.edit_key_user_ids); - mKeysList = (ListView) view.findViewById(R.id.edit_key_keys); + mSubkeysList = (ListView) view.findViewById(R.id.edit_key_keys); mUserIdsAddedList = (ListView) view.findViewById(R.id.edit_key_user_ids_added); mKeysAddedList = (ListView) view.findViewById(R.id.edit_key_keys_added); mChangePassphrase = view.findViewById(R.id.edit_key_action_change_passphrase); @@ -191,13 +191,13 @@ public class EditKeyFragment extends LoaderFragment implements } }); - // TODO: from savedInstance?! + // TODO: mUserIdsAddedData and SaveParcel from savedInstance?! mUserIdsAddedData = new ArrayList(); mUserIdsAddedAdapter = new UserIdsAddedAdapter(getActivity(), mUserIdsAddedData); mUserIdsAddedList.setAdapter(mUserIdsAddedAdapter); - mKeysAdapter = new SubkeysAdapter(getActivity(), null, 0); - mKeysList.setAdapter(mKeysAdapter); + mSubkeysAdapter = new SubkeysAdapter(getActivity(), null, 0); + mSubkeysList.setAdapter(mSubkeysAdapter); // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. @@ -235,7 +235,7 @@ public class EditKeyFragment extends LoaderFragment implements break; case LOADER_ID_KEYS: - mKeysAdapter.swapCursor(data); + mSubkeysAdapter.swapCursor(data); break; } @@ -252,7 +252,7 @@ public class EditKeyFragment extends LoaderFragment implements mUserIdsAdapter.swapCursor(null); break; case LOADER_ID_KEYS: - mKeysAdapter.swapCursor(null); + mSubkeysAdapter.swapCursor(null); break; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java index 6d8455589..f5f4b32e6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java @@ -38,22 +38,11 @@ import java.util.Date; public class SubkeysAdapter extends CursorAdapter { private LayoutInflater mInflater; - private int mIndexKeyId; - private int mIndexAlgorithm; - private int mIndexKeySize; - private int mIndexRank; - private int mIndexCanCertify; - private int mIndexCanEncrypt; - private int mIndexCanSign; - private int mIndexHasSecret; - private int mIndexRevokedKey; - private int mIndexExpiry; - private boolean hasAnySecret; private ColorStateList mDefaultTextColor; - public static final String[] KEYS_PROJECTION = new String[] { + public static final String[] KEYS_PROJECTION = new String[]{ Keys._ID, Keys.KEY_ID, Keys.RANK, @@ -68,24 +57,33 @@ public class SubkeysAdapter extends CursorAdapter { Keys.EXPIRY, Keys.FINGERPRINT }; + private static final int INDEX_ID = 0; + private static final int INDEX_KEY_ID = 1; + private static final int INDEX_RANK = 2; + private static final int INDEX_ALGORITHM = 3; + private static final int INDEX_KEY_SIZE = 4; + private static final int INDEX_HAS_SECRET = 5; + private static final int INDEX_CAN_CERTIFY = 6; + private static final int INDEX_CAN_ENCRYPT = 7; + private static final int INDEX_CAN_SIGN = 8; + private static final int INDEX_IS_REVOKED = 9; + private static final int INDEX_CREATION = 10; + private static final int INDEX_EXPIRY = 11; + private static final int INDEX_FINGERPRINT = 12; public SubkeysAdapter(Context context, Cursor c, int flags) { super(context, c, flags); mInflater = LayoutInflater.from(context); - - initIndex(c); } @Override public Cursor swapCursor(Cursor newCursor) { - initIndex(newCursor); - hasAnySecret = false; if (newCursor != null) { newCursor.moveToFirst(); do { - if (newCursor.getInt(mIndexHasSecret) != 0) { + if (newCursor.getInt(INDEX_HAS_SECRET) != 0) { hasAnySecret = true; break; } @@ -95,27 +93,6 @@ public class SubkeysAdapter extends CursorAdapter { return super.swapCursor(newCursor); } - /** - * Get column indexes for performance reasons just once in constructor and swapCursor. For a - * performance comparison see http://stackoverflow.com/a/17999582 - * - * @param cursor - */ - private void initIndex(Cursor cursor) { - if (cursor != null) { - mIndexKeyId = cursor.getColumnIndexOrThrow(Keys.KEY_ID); - mIndexAlgorithm = cursor.getColumnIndexOrThrow(Keys.ALGORITHM); - mIndexKeySize = cursor.getColumnIndexOrThrow(Keys.KEY_SIZE); - mIndexRank = cursor.getColumnIndexOrThrow(Keys.RANK); - mIndexCanCertify = cursor.getColumnIndexOrThrow(Keys.CAN_CERTIFY); - mIndexCanEncrypt = cursor.getColumnIndexOrThrow(Keys.CAN_ENCRYPT); - mIndexCanSign = cursor.getColumnIndexOrThrow(Keys.CAN_SIGN); - mIndexHasSecret = cursor.getColumnIndexOrThrow(Keys.HAS_SECRET); - mIndexRevokedKey = cursor.getColumnIndexOrThrow(Keys.IS_REVOKED); - mIndexExpiry = cursor.getColumnIndexOrThrow(Keys.EXPIRY); - } - } - @Override public void bindView(View view, Context context, Cursor cursor) { TextView keyId = (TextView) view.findViewById(R.id.keyId); @@ -127,16 +104,16 @@ public class SubkeysAdapter extends CursorAdapter { ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey); ImageView revokedKeyIcon = (ImageView) view.findViewById(R.id.ic_revokedKey); - String keyIdStr = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId)); + String keyIdStr = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(INDEX_KEY_ID)); String algorithmStr = PgpKeyHelper.getAlgorithmInfo( context, - cursor.getInt(mIndexAlgorithm), - cursor.getInt(mIndexKeySize) + cursor.getInt(INDEX_ALGORITHM), + cursor.getInt(INDEX_KEY_SIZE) ); keyId.setText(keyIdStr); // may be set with additional "stripped" later on - if (hasAnySecret && cursor.getInt(mIndexHasSecret) == 0) { + if (hasAnySecret && cursor.getInt(INDEX_HAS_SECRET) == 0) { keyDetails.setText(algorithmStr + ", " + context.getString(R.string.key_stripped)); } else { @@ -144,13 +121,13 @@ public class SubkeysAdapter extends CursorAdapter { } // Set icons according to properties - masterKeyIcon.setVisibility(cursor.getInt(mIndexRank) == 0 ? View.VISIBLE : View.INVISIBLE); - certifyIcon.setVisibility(cursor.getInt(mIndexCanCertify) != 0 ? View.VISIBLE : View.GONE); - encryptIcon.setVisibility(cursor.getInt(mIndexCanEncrypt) != 0 ? View.VISIBLE : View.GONE); - signIcon.setVisibility(cursor.getInt(mIndexCanSign) != 0 ? View.VISIBLE : View.GONE); + masterKeyIcon.setVisibility(cursor.getInt(INDEX_RANK) == 0 ? View.VISIBLE : View.INVISIBLE); + certifyIcon.setVisibility(cursor.getInt(INDEX_CAN_CERTIFY) != 0 ? View.VISIBLE : View.GONE); + encryptIcon.setVisibility(cursor.getInt(INDEX_CAN_ENCRYPT) != 0 ? View.VISIBLE : View.GONE); + signIcon.setVisibility(cursor.getInt(INDEX_CAN_SIGN) != 0 ? View.VISIBLE : View.GONE); boolean valid = true; - if (cursor.getInt(mIndexRevokedKey) > 0) { + if (cursor.getInt(INDEX_IS_REVOKED) > 0) { revokedKeyIcon.setVisibility(View.VISIBLE); valid = false; @@ -162,17 +139,19 @@ public class SubkeysAdapter extends CursorAdapter { revokedKeyIcon.setVisibility(View.GONE); } - if (!cursor.isNull(mIndexExpiry)) { - Date expiryDate = new Date(cursor.getLong(mIndexExpiry) * 1000); + if (!cursor.isNull(INDEX_EXPIRY)) { + Date expiryDate = new Date(cursor.getLong(INDEX_EXPIRY) * 1000); valid = valid && expiryDate.after(new Date()); keyExpiry.setText( context.getString(R.string.label_expiry) + ": " + - DateFormat.getDateFormat(context).format(expiryDate)); + DateFormat.getDateFormat(context).format(expiryDate) + ); } else { keyExpiry.setText( context.getString(R.string.label_expiry) + ": " + - context.getString(R.string.none)); + context.getString(R.string.none) + ); } // if key is expired or revoked, strike through text diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index 7bf9334b8..47f17357a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -41,9 +41,6 @@ import java.util.ArrayList; public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemClickListener { private LayoutInflater mInflater; - private int mIndexUserId, mIndexRank; - private int mVerifiedId, mIsRevoked, mIsPrimary; - private final ArrayList mCheckStates; private SaveKeyringParcel mSaveKeyringParcel; @@ -56,6 +53,13 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC UserIds.IS_PRIMARY, UserIds.IS_REVOKED }; + private static final int INDEX_ID = 0; + private static final int INDEX_USER_ID = 1; + private static final int INDEX_RANK = 2; + private static final int INDEX_VERIFIED = 3; + private static final int INDEX_IS_PRIMARY = 4; + private static final int INDEX_IS_REVOKED = 5; + public UserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes, SaveKeyringParcel saveKeyringParcel) { @@ -64,8 +68,6 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC mCheckStates = showCheckBoxes ? new ArrayList() : null; mSaveKeyringParcel = saveKeyringParcel; - - initIndex(c); } public UserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes) { @@ -82,7 +84,6 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC @Override public Cursor swapCursor(Cursor newCursor) { - initIndex(newCursor); if (mCheckStates != null) { mCheckStates.clear(); if (newCursor != null) { @@ -91,7 +92,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC // initialize to true (use case knowledge: we usually want to sign all uids) for (int i = 0; i < count; i++) { newCursor.moveToPosition(i); - int verified = newCursor.getInt(mVerifiedId); + int verified = newCursor.getInt(INDEX_VERIFIED); mCheckStates.add(verified != Certs.VERIFIED_SECRET); } } @@ -100,22 +101,6 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC return super.swapCursor(newCursor); } - /** - * Get column indexes for performance reasons just once in constructor and swapCursor. For a - * performance comparison see http://stackoverflow.com/a/17999582 - * - * @param cursor - */ - private void initIndex(Cursor cursor) { - if (cursor != null) { - mIndexUserId = cursor.getColumnIndexOrThrow(UserIds.USER_ID); - mIndexRank = cursor.getColumnIndexOrThrow(UserIds.RANK); - mVerifiedId = cursor.getColumnIndexOrThrow(UserIds.VERIFIED); - mIsRevoked = cursor.getColumnIndexOrThrow(UserIds.IS_REVOKED); - mIsPrimary = cursor.getColumnIndexOrThrow(UserIds.IS_PRIMARY); - } - } - @Override public void bindView(View view, Context context, Cursor cursor) { TextView vName = (TextView) view.findViewById(R.id.userId); @@ -125,7 +110,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC ImageView vHasChanges = (ImageView) view.findViewById(R.id.has_changes); ImageView vEditImage = (ImageView) view.findViewById(R.id.edit_image); - String userId = cursor.getString(mIndexUserId); + String userId = cursor.getString(INDEX_USER_ID); String[] splitUserId = KeyRing.splitUserId(userId); if (splitUserId[0] != null) { vName.setText(splitUserId[0]); @@ -145,8 +130,8 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC vComment.setVisibility(View.GONE); } - boolean isPrimary = cursor.getInt(mIsPrimary) != 0; - boolean isRevoked = cursor.getInt(mIsRevoked) > 0; + boolean isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0; + boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0; // for edit key if (mSaveKeyringParcel != null) { @@ -189,7 +174,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC // verified: has been verified // isPrimary: show small star icon for primary user ids - int verified = cursor.getInt(mVerifiedId); + int verified = cursor.getInt(INDEX_VERIFIED); switch (verified) { case Certs.VERIFIED_SECRET: vVerified.setImageResource(isPrimary @@ -237,7 +222,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC for (int i = 0; i < mCheckStates.size(); i++) { if (mCheckStates.get(i)) { mCursor.moveToPosition(i); - result.add(mCursor.getString(mIndexUserId)); + result.add(mCursor.getString(INDEX_USER_ID)); } } return result; @@ -245,7 +230,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC public String getUserId(int position) { mCursor.moveToPosition(position); - return mCursor.getString(mIndexUserId); + return mCursor.getString(INDEX_USER_ID); } @Override -- cgit v1.2.3 From 13a13829a8b8ad49237fb9bc8bb5a03ff5a4cce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 2 Jul 2014 16:47:12 +0200 Subject: fix nullpointer, cleanup --- .../org/sufficientlysecure/keychain/ui/EditKeyFragment.java | 12 ++++++------ .../sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java | 2 +- .../keychain/ui/adapter/SubkeysAdapter.java | 5 ++--- 3 files changed, 9 insertions(+), 10 deletions(-) (limited to 'OpenKeychain/src') 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 8c7606cf9..b00049ac7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -73,7 +73,7 @@ public class EditKeyFragment extends LoaderFragment implements private View mAddKey; private static final int LOADER_ID_USER_IDS = 0; - private static final int LOADER_ID_KEYS = 1; + private static final int LOADER_ID_SUBKEYS = 1; private UserIdsAdapter mUserIdsAdapter; private SubkeysAdapter mSubkeysAdapter; @@ -202,7 +202,7 @@ public class EditKeyFragment extends LoaderFragment implements // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); - getLoaderManager().initLoader(LOADER_ID_KEYS, null, this); + getLoaderManager().initLoader(LOADER_ID_SUBKEYS, null, this); } public Loader onCreateLoader(int id, Bundle args) { @@ -215,10 +215,10 @@ public class EditKeyFragment extends LoaderFragment implements UserIdsAdapter.USER_IDS_PROJECTION, null, null, null); } - case LOADER_ID_KEYS: { + case LOADER_ID_SUBKEYS: { Uri baseUri = KeychainContract.Keys.buildKeysUri(mDataUri); return new CursorLoader(getActivity(), baseUri, - SubkeysAdapter.KEYS_PROJECTION, null, null, null); + SubkeysAdapter.SUBKEYS_PROJECTION, null, null, null); } default: @@ -234,7 +234,7 @@ public class EditKeyFragment extends LoaderFragment implements mUserIdsAdapter.swapCursor(data); break; - case LOADER_ID_KEYS: + case LOADER_ID_SUBKEYS: mSubkeysAdapter.swapCursor(data); break; @@ -251,7 +251,7 @@ public class EditKeyFragment extends LoaderFragment implements case LOADER_ID_USER_IDS: mUserIdsAdapter.swapCursor(null); break; - case LOADER_ID_KEYS: + case LOADER_ID_SUBKEYS: mSubkeysAdapter.swapCursor(null); break; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java index 4be572b4e..e46637871 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java @@ -87,7 +87,7 @@ public class ViewKeyKeysFragment extends LoaderFragment implements setContentShown(false); Uri baseUri = Keys.buildKeysUri(mDataUri); return new CursorLoader(getActivity(), baseUri, - SubkeysAdapter.KEYS_PROJECTION, null, null, null); + SubkeysAdapter.SUBKEYS_PROJECTION, null, null, null); } public void onLoadFinished(Loader loader, Cursor data) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java index f5f4b32e6..02b1f31e2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java @@ -42,7 +42,7 @@ public class SubkeysAdapter extends CursorAdapter { private ColorStateList mDefaultTextColor; - public static final String[] KEYS_PROJECTION = new String[]{ + public static final String[] SUBKEYS_PROJECTION = new String[]{ Keys._ID, Keys.KEY_ID, Keys.RANK, @@ -80,8 +80,7 @@ public class SubkeysAdapter extends CursorAdapter { @Override public Cursor swapCursor(Cursor newCursor) { hasAnySecret = false; - if (newCursor != null) { - newCursor.moveToFirst(); + if (newCursor != null && newCursor.moveToFirst()) { do { if (newCursor.getInt(INDEX_HAS_SECRET) != 0) { hasAnySecret = true; -- cgit v1.2.3 From 12db94abca69b42323c47cd19441f203784a2888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 2 Jul 2014 18:59:23 +0200 Subject: A little bit less purple --- OpenKeychain/src/main/res/layout/decrypt_content.xml | 5 ++--- OpenKeychain/src/main/res/layout/encrypt_content.xml | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/res/layout/decrypt_content.xml b/OpenKeychain/src/main/res/layout/decrypt_content.xml index ff75f20ee..f62cf615c 100644 --- a/OpenKeychain/src/main/res/layout/decrypt_content.xml +++ b/OpenKeychain/src/main/res/layout/decrypt_content.xml @@ -6,7 +6,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - + + android:textColor="@color/emphasis" /> \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/encrypt_content.xml b/OpenKeychain/src/main/res/layout/encrypt_content.xml index e719d07e1..a9a7db3e5 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_content.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_content.xml @@ -16,8 +16,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" - android:background="@color/emphasis" - android:textColor="#fff" /> + android:textColor="@color/emphasis" /> + android:textColor="@color/emphasis" /> \ No newline at end of file -- cgit v1.2.3 From 3512ac71994c4e2df039b342b982de91726344ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 2 Jul 2014 20:53:16 +0200 Subject: Remove unnecessary error logs --- .../main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java | 2 +- .../main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 5b21be6e4..dba742268 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -170,7 +170,7 @@ public class DecryptActivity extends DrawerActivity { // end activity finish(); } - } else { + } else if (ACTION_DECRYPT.equals(action)) { Log.e(Constants.TAG, "Include the extra 'text' or an Uri with setData() in your Intent!"); } 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 39d4a09bc..cc69148c1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -249,7 +249,7 @@ public class EncryptActivity extends DrawerActivity implements // end activity finish(); } - } else { + } else if (ACTION_ENCRYPT.equals(action)) { Log.e(Constants.TAG, "Include the extra 'text' or an Uri with setData() in your Intent!"); } -- cgit v1.2.3 From 8cbdf7b1c514f7b9148e1fef1a6776666d1e04aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 3 Jul 2014 08:48:33 +0200 Subject: smaller dropdown items --- .../main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java | 4 ++-- .../sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java index 20b47ed01..601fc09f9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java @@ -142,7 +142,7 @@ public class WizardActivity extends ActionBarActivity { emailView.setThreshold(1); // Start working from first character emailView.setAdapter( new ArrayAdapter - (getActivity(), android.R.layout.simple_dropdown_item_1line, + (getActivity(), android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserEmails(getActivity()) ) ); @@ -177,7 +177,7 @@ public class WizardActivity extends ActionBarActivity { nameView.setThreshold(1); // Start working from first character nameView.setAdapter( new ArrayAdapter - (getActivity(), android.R.layout.simple_dropdown_item_1line, + (getActivity(), android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserNames(getActivity()) ) ); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java index 137217ff4..898e60e2d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java @@ -72,11 +72,11 @@ public class UserIdsAddedAdapter extends ArrayAdapter - (mActivity, android.R.layout.simple_dropdown_item_1line, + (mActivity, android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserNames(mActivity) ); mAutoCompleteEmailAdapter = new ArrayAdapter - (mActivity, android.R.layout.simple_dropdown_item_1line, + (mActivity, android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserEmails(mActivity) ); } -- cgit v1.2.3 From 55f067b0633a177c2d441a7c79115dd44d7c4a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 3 Jul 2014 15:05:43 +0200 Subject: Work on edit --- .../keychain/service/SaveKeyringParcel.java | 14 ++++---- .../keychain/ui/EditKeyFragment.java | 30 +++++++++++++--- .../keychain/ui/adapter/UserIdsAdapter.java | 22 ++++++------ .../keychain/ui/adapter/UserIdsAddedAdapter.java | 40 +++++++++++----------- .../ui/dialog/CreateKeyDialogFragment.java | 8 ++--- .../res/layout/edit_key_user_id_added_item.xml | 1 - .../src/main/res/layout/view_key_userids_item.xml | 7 ---- OpenKeychain/src/main/res/values/strings.xml | 7 ++-- 8 files changed, 69 insertions(+), 60 deletions(-) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index 1ad19cdd0..c48cf4b3b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -55,10 +55,10 @@ public class SaveKeyringParcel implements Parcelable { // performance gain for using Parcelable here would probably be negligible, // use Serializable instead. public static class SubkeyAdd implements Serializable { - public final int mAlgorithm; - public final int mKeysize; - public final int mFlags; - public final Long mExpiry; + public int mAlgorithm; + public int mKeysize; + public int mFlags; + public Long mExpiry; public SubkeyAdd(int algorithm, int keysize, int flags, Long expiry) { mAlgorithm = algorithm; mKeysize = keysize; @@ -68,9 +68,9 @@ public class SaveKeyringParcel implements Parcelable { } public static class SubkeyChange implements Serializable { - public final long mKeyId; - public final Integer mFlags; - public final Long mExpiry; + public long mKeyId; + public Integer mFlags; + public Long mExpiry; public SubkeyChange(long keyId, Integer flags, Long expiry) { mKeyId = keyId; mFlags = flags; 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 b00049ac7..97e4ffca9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -37,6 +37,7 @@ import android.widget.AdapterView; import android.widget.ListView; import android.widget.Toast; +import org.spongycastle.bcpg.sig.KeyFlags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; @@ -50,6 +51,7 @@ import org.sufficientlysecure.keychain.service.OperationResults; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; 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.dialog.EditUserIdDialogFragment; @@ -67,17 +69,22 @@ public class EditKeyFragment extends LoaderFragment implements private ListView mUserIdsList; private ListView mSubkeysList; private ListView mUserIdsAddedList; - private ListView mKeysAddedList; + private ListView mSubkeysAddedList; private View mChangePassphrase; private View mAddUserId; - private View mAddKey; + private View mAddSubkey; private static final int LOADER_ID_USER_IDS = 0; private static final int LOADER_ID_SUBKEYS = 1; + // cursor adapter private UserIdsAdapter mUserIdsAdapter; private SubkeysAdapter mSubkeysAdapter; + + // array adapter private UserIdsAddedAdapter mUserIdsAddedAdapter; + private SubkeysAddedAdapter mSubkeysAddedAdapter; + private ArrayList mUserIdsAddedData; private Uri mDataUri; @@ -106,10 +113,10 @@ public class EditKeyFragment extends LoaderFragment implements mUserIdsList = (ListView) view.findViewById(R.id.edit_key_user_ids); mSubkeysList = (ListView) view.findViewById(R.id.edit_key_keys); mUserIdsAddedList = (ListView) view.findViewById(R.id.edit_key_user_ids_added); - mKeysAddedList = (ListView) view.findViewById(R.id.edit_key_keys_added); + mSubkeysAddedList = (ListView) view.findViewById(R.id.edit_key_keys_added); mChangePassphrase = view.findViewById(R.id.edit_key_action_change_passphrase); mAddUserId = view.findViewById(R.id.edit_key_action_add_user_id); - mAddKey = view.findViewById(R.id.edit_key_action_add_key); + mAddSubkey = view.findViewById(R.id.edit_key_action_add_key); return root; } @@ -180,6 +187,13 @@ public class EditKeyFragment extends LoaderFragment implements } }); + mAddSubkey.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + addSubkey(); + } + }); + mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, mSaveKeyringParcel); mUserIdsList.setAdapter(mUserIdsAdapter); @@ -199,6 +213,9 @@ public class EditKeyFragment extends LoaderFragment implements mSubkeysAdapter = new SubkeysAdapter(getActivity(), null, 0); mSubkeysList.setAdapter(mSubkeysAdapter); + mSubkeysAddedAdapter = new SubkeysAddedAdapter(getActivity(), mSaveKeyringParcel.addSubKeys); + mSubkeysAddedList.setAdapter(mSubkeysAddedAdapter); + // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); @@ -327,6 +344,11 @@ public class EditKeyFragment extends LoaderFragment implements mUserIdsAddedAdapter.add(new UserIdsAddedAdapter.UserIdModel()); } + private void addSubkey() { + // default values + mSubkeysAddedAdapter.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.SIGN_DATA, null)); + } + private void save() { String passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), mSaveKeyringParcel.mMasterKeyId); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index 47f17357a..d729648e5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -107,7 +107,6 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC TextView vAddress = (TextView) view.findViewById(R.id.address); TextView vComment = (TextView) view.findViewById(R.id.comment); ImageView vVerified = (ImageView) view.findViewById(R.id.certified); - ImageView vHasChanges = (ImageView) view.findViewById(R.id.has_changes); ImageView vEditImage = (ImageView) view.findViewById(R.id.edit_image); String userId = cursor.getString(INDEX_USER_ID); @@ -135,27 +134,23 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC // for edit key if (mSaveKeyringParcel != null) { - boolean changeUserId = (mSaveKeyringParcel.changePrimaryUserId != null + boolean changeAnyPrimaryUserId = (mSaveKeyringParcel.changePrimaryUserId != null); + boolean changeThisPrimaryUserId = (mSaveKeyringParcel.changePrimaryUserId != null && mSaveKeyringParcel.changePrimaryUserId.equals(userId)); - boolean revoke = (mSaveKeyringParcel.revokeUserIds.contains(userId)); + boolean revokeThisUserId = (mSaveKeyringParcel.revokeUserIds.contains(userId)); - if (changeUserId) { - isPrimary = !isPrimary; + if (changeAnyPrimaryUserId) { + // change all user ids, only this one should be primary + isPrimary = changeThisPrimaryUserId; } - if (revoke) { + if (revokeThisUserId) { if (!isRevoked) { isRevoked = true; } } - if (changeUserId || revoke) { - vHasChanges.setVisibility(View.VISIBLE); - } else { - vHasChanges.setVisibility(View.GONE); - } vEditImage.setVisibility(View.VISIBLE); } else { - vHasChanges.setVisibility(View.GONE); vEditImage.setVisibility(View.GONE); } @@ -166,11 +161,14 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC // disable and strike through text for revoked user ids vName.setEnabled(false); vAddress.setEnabled(false); + vComment.setEnabled(false); vName.setText(OtherHelper.strikeOutText(vName.getText())); vAddress.setText(OtherHelper.strikeOutText(vAddress.getText())); + vComment.setText(OtherHelper.strikeOutText(vComment.getText())); } else { vName.setEnabled(true); vAddress.setEnabled(true); + vComment.setEnabled(true); // verified: has been verified // isPrimary: show small star icon for primary user ids diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java index 898e60e2d..3fe5574ee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java @@ -106,14 +106,14 @@ public class UserIdsAddedAdapter extends ArrayAdapter 0) { - Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(viewHolder.mModel.address); + if (holder.mModel.address.length() > 0) { + Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(holder.mModel.address); if (emailMatcher.matches()) { - viewHolder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, + holder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.uid_mail_ok, 0); } else { - viewHolder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, + holder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.uid_mail_bad, 0); } } else { // remove drawable if email is empty - viewHolder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + holder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } } }); - viewHolder.vName.addTextChangedListener(new TextWatcher() { + holder.vName.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @@ -156,11 +156,11 @@ public class UserIdsAddedAdapter extends ArrayAdapter - - Successfully exported %d keys. No keys exported. Note: only subkeys support ElGamal. - Note: generating RSA key with length 1024-bit and less is considered unsafe and it\'s disabled for generating new keys. Couldn\'t find key %08X. @@ -626,8 +625,8 @@ Modifying keyring %s Encoding exception! - Actual key fingerprint does not match expected! - No keyid. This is a programming error, please file a bug report! + Actual key fingerprint does not match the expected one! + No key ID. This is an internal error, please file a bug report! Internal error, integrity check failed! Revoked user ids cannot be primary! PGP internal exception! @@ -636,7 +635,7 @@ Modifying subkey %s Tried to operate on missing subkey %s! Generating new %1$s bit %2$s subkey - New subkey id: %s + New subkey ID: %s Expiry date cannot be in the past! Revoking subkey %s Keyring successfully modified -- cgit v1.2.3 From 42cc8b687b60254396450a07814ffee8d10b3224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 3 Jul 2014 15:14:06 +0200 Subject: edit key: subkey adapter --- .../keychain/ui/EditKeyFragment.java | 2 +- .../keychain/ui/adapter/SubkeysAddedAdapter.java | 360 +++++++++++++++++++++ .../src/main/res/layout/edit_key_fragment.xml | 2 +- .../main/res/layout/edit_key_subkey_added_item.xml | 96 ++++++ 4 files changed, 458 insertions(+), 2 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java create mode 100644 OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml (limited to 'OpenKeychain/src') 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 97e4ffca9..e651ed269 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -113,7 +113,7 @@ public class EditKeyFragment extends LoaderFragment implements mUserIdsList = (ListView) view.findViewById(R.id.edit_key_user_ids); mSubkeysList = (ListView) view.findViewById(R.id.edit_key_keys); mUserIdsAddedList = (ListView) view.findViewById(R.id.edit_key_user_ids_added); - mSubkeysAddedList = (ListView) view.findViewById(R.id.edit_key_keys_added); + mSubkeysAddedList = (ListView) view.findViewById(R.id.edit_key_subkeys_added); mChangePassphrase = view.findViewById(R.id.edit_key_action_change_passphrase); mAddUserId = view.findViewById(R.id.edit_key_action_add_user_id); mAddSubkey = view.findViewById(R.id.edit_key_action_add_key); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java new file mode 100644 index 000000000..e42140ee6 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java @@ -0,0 +1,360 @@ +/* + * 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.adapter; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Build; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.Patterns; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.InputMethodManager; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.Spinner; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.helper.ContactHelper; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.ui.dialog.CreateKeyDialogFragment; +import org.sufficientlysecure.keychain.util.Choice; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; + +public class SubkeysAddedAdapter extends ArrayAdapter { + private LayoutInflater mInflater; + private Activity mActivity; + + public interface OnAlgorithmSelectedListener { + public void onAlgorithmSelected(Choice algorithmChoice, int keySize); + } + + // hold a private reference to the underlying data List + private List mData; + + public SubkeysAddedAdapter(Activity activity, List data) { + super(activity, -1, data); + mActivity = activity; + mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mData = data; + } + + static class ViewHolder { + public OnAlgorithmSelectedListener mAlgorithmSelectedListener; + public Spinner mAlgorithmSpinner; + public Spinner mKeySizeSpinner; + public TextView mCustomKeyTextView; + public EditText mCustomKeyEditText; + public TextView mCustomKeyInfoTextView; + public ImageButton vDelete; + // also hold a reference to the model item + public SaveKeyringParcel.SubkeyAdd mModel; + } + + public View getView(final int position, View convertView, ViewGroup parent) { + if (convertView == null) { + // Not recycled, inflate a new view + convertView = mInflater.inflate(R.layout.edit_key_subkey_added_item, null); + final ViewHolder holder = new ViewHolder(); + holder.mAlgorithmSpinner = (Spinner) convertView.findViewById(R.id.create_key_algorithm); + holder.mKeySizeSpinner = (Spinner) convertView.findViewById(R.id.create_key_size); + holder.mCustomKeyTextView = (TextView) convertView.findViewById(R.id.custom_key_size_label); + holder.mCustomKeyEditText = (EditText) convertView.findViewById(R.id.custom_key_size_input); + holder.mCustomKeyInfoTextView = (TextView) convertView.findViewById(R.id.custom_key_size_info); + holder.vDelete = (ImageButton) convertView.findViewById(R.id.subkey_added_item_delete); + convertView.setTag(holder); + + holder.mAlgorithmSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + Choice newKeyAlgorithmChoice = (Choice) holder.mAlgorithmSpinner.getSelectedItem(); + // update referenced model item + holder.mModel.mAlgorithm = newKeyAlgorithmChoice.getId(); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + + holder.mKeySizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + Choice newKeyAlgorithmChoice = (Choice) holder.mAlgorithmSpinner.getSelectedItem(); + int newKeySize = getProperKeyLength(newKeyAlgorithmChoice.getId(), + getSelectedKeyLength(holder.mKeySizeSpinner, holder.mCustomKeyEditText)); + // update referenced model item + holder.mModel.mKeysize = newKeySize; + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + + holder.vDelete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // remove reference model item from adapter (data and notify about change) + SubkeysAddedAdapter.this.remove(holder.mModel); + } + }); + + } + final ViewHolder holder = (ViewHolder) convertView.getTag(); + + // save reference to model item + holder.mModel = getItem(position); + + // TODO + boolean wouldBeMasterKey = false; +// boolean wouldBeMasterKey = (childCount == 0); + + ArrayList choices = new ArrayList(); + choices.add(new Choice(Constants.choice.algorithm.dsa, mActivity.getResources().getString( + R.string.dsa))); + if (!wouldBeMasterKey) { + choices.add(new Choice(Constants.choice.algorithm.elgamal, mActivity.getResources().getString( + R.string.elgamal))); + } + + choices.add(new Choice(Constants.choice.algorithm.rsa, mActivity.getResources().getString( + R.string.rsa))); + + ArrayAdapter adapter = new ArrayAdapter(mActivity, + android.R.layout.simple_spinner_item, choices); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + holder.mAlgorithmSpinner.setAdapter(adapter); + // make RSA the default + for (int i = 0; i < choices.size(); ++i) { + if (choices.get(i).getId() == Constants.choice.algorithm.rsa) { + holder.mAlgorithmSpinner.setSelection(i); + break; + } + } + + // dynamic ArrayAdapter must be created (instead of ArrayAdapter.getFromResource), because it's content may change + ArrayAdapter keySizeAdapter = new ArrayAdapter(mActivity, android.R.layout.simple_spinner_item, + new ArrayList(Arrays.asList(mActivity.getResources().getStringArray(R.array.rsa_key_size_spinner_values)))); + keySizeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + holder.mKeySizeSpinner.setAdapter(keySizeAdapter); + holder.mKeySizeSpinner.setSelection(1); // Default to 4096 for the key length + + holder.mCustomKeyEditText.addTextChangedListener(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) { +// setOkButtonAvailability(alertDialog); + } + }); + + holder.mKeySizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + setCustomKeyVisibility(holder.mKeySizeSpinner, holder.mCustomKeyEditText, + holder.mCustomKeyTextView, holder.mCustomKeyInfoTextView); +// setOkButtonAvailability(alertDialog); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + + holder.mAlgorithmSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + setKeyLengthSpinnerValuesForAlgorithm(((Choice) parent.getSelectedItem()).getId(), + holder.mKeySizeSpinner, holder.mCustomKeyInfoTextView); + + setCustomKeyVisibility(holder.mKeySizeSpinner, holder.mCustomKeyEditText, + holder.mCustomKeyTextView, holder.mCustomKeyInfoTextView); +// setOkButtonAvailability(alertDialog); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); +// +// holder.vAddress.setText(holder.mModel.address); +// holder.vAddress.setThreshold(1); // Start working from first character +// holder.vAddress.setAdapter(mAutoCompleteEmailAdapter); +// +// holder.vName.setText(holder.mModel.name); +// holder.vName.setThreshold(1); // Start working from first character +// holder.vName.setAdapter(mAutoCompleteNameAdapter); +// +// holder.vComment.setText(holder.mModel.comment); + + return convertView; + } + + + private int getSelectedKeyLength(Spinner keySizeSpinner, EditText customKeyEditText) { + final String selectedItemString = (String) keySizeSpinner.getSelectedItem(); + final String customLengthString = mActivity.getResources().getString(R.string.key_size_custom); + final boolean customSelected = customLengthString.equals(selectedItemString); + String keyLengthString = customSelected ? customKeyEditText.getText().toString() : selectedItemString; + int keySize; + try { + keySize = Integer.parseInt(keyLengthString); + } catch (NumberFormatException e) { + keySize = 0; + } + return keySize; + } + + /** + *

RSA

+ *

for RSA algorithm, key length must be greater than 1024 (according to + * #102). Possibility to generate keys bigger + * than 8192 bits is currently disabled, because it's almost impossible to generate them on a mobile device (check + * RSA key length plot and + * Cryptographic Key Length Recommendation). Also, key length must be a + * multiplicity of 8.

+ *

ElGamal

+ *

For ElGamal algorithm, supported key lengths are 1536, 2048, 3072, 4096 or 8192 bits.

+ *

DSA

+ *

For DSA algorithm key length must be between 512 and 1024. Also, it must me dividable by 64.

+ * + * @return correct key length, according to SpongyCastle specification. Returns -1, if key length is + * inappropriate. + */ + private int getProperKeyLength(int algorithmId, int currentKeyLength) { + final int[] elGamalSupportedLengths = {1536, 2048, 3072, 4096, 8192}; + int properKeyLength = -1; + switch (algorithmId) { + case Constants.choice.algorithm.rsa: + if (currentKeyLength > 1024 && currentKeyLength <= 8192) { + properKeyLength = currentKeyLength + ((8 - (currentKeyLength % 8)) % 8); + } + break; + case Constants.choice.algorithm.elgamal: + int[] elGammalKeyDiff = new int[elGamalSupportedLengths.length]; + for (int i = 0; i < elGamalSupportedLengths.length; i++) { + elGammalKeyDiff[i] = Math.abs(elGamalSupportedLengths[i] - currentKeyLength); + } + int minimalValue = Integer.MAX_VALUE; + int minimalIndex = -1; + for (int i = 0; i < elGammalKeyDiff.length; i++) { + if (elGammalKeyDiff[i] <= minimalValue) { + minimalValue = elGammalKeyDiff[i]; + minimalIndex = i; + } + } + properKeyLength = elGamalSupportedLengths[minimalIndex]; + break; + case Constants.choice.algorithm.dsa: + if (currentKeyLength >= 512 && currentKeyLength <= 1024) { + properKeyLength = currentKeyLength + ((64 - (currentKeyLength % 64)) % 64); + } + break; + } + return properKeyLength; + } + +// private boolean setOkButtonAvailability(AlertDialog alertDialog) { +// final Choice selectedAlgorithm = (Choice) mAlgorithmSpinner.getSelectedItem(); +// final int selectedKeySize = getSelectedKeyLength(); //Integer.parseInt((String) mKeySizeSpinner.getSelectedItem()); +// final int properKeyLength = getProperKeyLength(selectedAlgorithm.getId(), selectedKeySize); +// alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(properKeyLength > 0); +// } + + private void setCustomKeyVisibility(Spinner keySizeSpinner, EditText customkeyedittext, TextView customKeyTextView, TextView customKeyInfoTextView) { + final String selectedItemString = (String) keySizeSpinner.getSelectedItem(); + final String customLengthString = mActivity.getResources().getString(R.string.key_size_custom); + final boolean customSelected = customLengthString.equals(selectedItemString); + final int visibility = customSelected ? View.VISIBLE : View.GONE; + + customkeyedittext.setVisibility(visibility); + customKeyTextView.setVisibility(visibility); + customKeyInfoTextView.setVisibility(visibility); + + // hide keyboard after setting visibility to gone + if (visibility == View.GONE) { + InputMethodManager imm = (InputMethodManager) + mActivity.getSystemService(mActivity.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(customkeyedittext.getWindowToken(), 0); + } + } + + private void setKeyLengthSpinnerValuesForAlgorithm(int algorithmId, Spinner keySizeSpinner, TextView customKeyInfoTextView) { + final ArrayAdapter keySizeAdapter = (ArrayAdapter) keySizeSpinner.getAdapter(); + final Object selectedItem = keySizeSpinner.getSelectedItem(); + keySizeAdapter.clear(); + switch (algorithmId) { + case Constants.choice.algorithm.rsa: + replaceArrayAdapterContent(keySizeAdapter, R.array.rsa_key_size_spinner_values); + customKeyInfoTextView.setText(mActivity.getResources().getString(R.string.key_size_custom_info_rsa)); + break; + case Constants.choice.algorithm.elgamal: + replaceArrayAdapterContent(keySizeAdapter, R.array.elgamal_key_size_spinner_values); + customKeyInfoTextView.setText(""); // ElGamal does not support custom key length + break; + case Constants.choice.algorithm.dsa: + replaceArrayAdapterContent(keySizeAdapter, R.array.dsa_key_size_spinner_values); + customKeyInfoTextView.setText(mActivity.getResources().getString(R.string.key_size_custom_info_dsa)); + break; + } + keySizeAdapter.notifyDataSetChanged(); + + // when switching algorithm, try to select same key length as before + for (int i = 0; i < keySizeAdapter.getCount(); i++) { + if (selectedItem.equals(keySizeAdapter.getItem(i))) { + keySizeSpinner.setSelection(i); + break; + } + } + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void replaceArrayAdapterContent(ArrayAdapter arrayAdapter, int stringArrayResourceId) { + final String[] spinnerValuesStringArray = mActivity.getResources().getStringArray(stringArrayResourceId); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + arrayAdapter.addAll(spinnerValuesStringArray); + } else { + for (final String value : spinnerValuesStringArray) { + arrayAdapter.add(value); + } + } + } + +} diff --git a/OpenKeychain/src/main/res/layout/edit_key_fragment.xml b/OpenKeychain/src/main/res/layout/edit_key_fragment.xml index 05e6c09c5..0570784d0 100644 --- a/OpenKeychain/src/main/res/layout/edit_key_fragment.xml +++ b/OpenKeychain/src/main/res/layout/edit_key_fragment.xml @@ -93,7 +93,7 @@ android:background="?android:attr/listDivider" /> diff --git a/OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml b/OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml new file mode 100644 index 000000000..f52d693e0 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file -- cgit v1.2.3 From 9cbf78f7add8a0ea263c9485c58c848b10a0678c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 3 Jul 2014 15:24:04 +0200 Subject: cleanup --- .../main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java | 4 ++++ .../sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java | 1 + 2 files changed, 5 insertions(+) (limited to 'OpenKeychain/src') 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 e651ed269..9d5a7e4ff 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -287,6 +287,7 @@ public class EditKeyFragment extends LoaderFragment implements .getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE); mSaveKeyringParcel.newPassphrase = newPassphrase; + Log.d(Constants.TAG, "newPassphrase set"); } } }; @@ -385,6 +386,9 @@ public class EditKeyFragment extends LoaderFragment implements super.handleMessage(message); if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { + getActivity().finish(); + + // TODO below // get returned data bundle Bundle returnData = message.getData(); if (returnData == null) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java index e42140ee6..25509fee5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java @@ -291,6 +291,7 @@ public class SubkeysAddedAdapter extends ArrayAdapter Date: Thu, 3 Jul 2014 15:28:45 +0200 Subject: parcel newPassphrase --- .../org/sufficientlysecure/keychain/service/SaveKeyringParcel.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'OpenKeychain/src') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index c48cf4b3b..a56095767 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -82,6 +82,8 @@ public class SaveKeyringParcel implements Parcelable { mMasterKeyId = source.readInt() != 0 ? source.readLong() : null; mFingerprint = source.createByteArray(); + newPassphrase = source.readString(); + addUserIds = source.createStringArrayList(); addSubKeys = (ArrayList) source.readSerializable(); @@ -100,6 +102,8 @@ public class SaveKeyringParcel implements Parcelable { } destination.writeByteArray(mFingerprint); + destination.writeString(newPassphrase); + destination.writeStringList(addUserIds); destination.writeSerializable(addSubKeys); -- cgit v1.2.3 From 2988ac6e7b9fd997dad7ce9da66645a2d84e74a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 3 Jul 2014 15:48:46 +0200 Subject: Cache passphrase for edit --- .../keychain/ui/EditKeyActivity.java | 2 +- .../keychain/ui/EditKeyFragment.java | 23 +++--- .../ui/dialog/SetPassphraseDialogFragment.java | 65 ++++++++++++----- .../main/res/layout/edit_key_subkey_added_item.xml | 83 ++++++++++++++++++++++ .../main/res/layout/passphrase_repeat_dialog.xml | 16 +++-- 5 files changed, 152 insertions(+), 37 deletions(-) (limited to 'OpenKeychain/src') 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 906ed347e..76ef9bf6a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -357,7 +357,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener } SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance( - messenger, title); + messenger, null, title); setPassphraseDialog.show(getSupportFragmentManager(), "setPassphraseDialog"); } 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 9d5a7e4ff..46d3e9718 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -91,6 +91,8 @@ public class EditKeyFragment extends LoaderFragment implements private SaveKeyringParcel mSaveKeyringParcel; + private String mCurrentPassphrase; + /** * Creates new instance of this fragment */ @@ -125,6 +127,8 @@ public class EditKeyFragment extends LoaderFragment implements public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); + cachePassphraseForEdit(); + // Inflate a "Done"/"Cancel" custom action bar view ActionBarHelper.setTwoButtonView(((ActionBarActivity) getActivity()).getSupportActionBar(), R.string.btn_save, R.drawable.ic_action_save, @@ -132,7 +136,7 @@ public class EditKeyFragment extends LoaderFragment implements @Override public void onClick(View v) { // Save - save(); + save(mCurrentPassphrase); } }, R.string.menu_key_edit_cancel, R.drawable.ic_action_cancel, new OnClickListener() { @@ -296,7 +300,7 @@ public class EditKeyFragment extends LoaderFragment implements Messenger messenger = new Messenger(returnHandler); SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance( - messenger, R.string.title_change_passphrase); + messenger, mCurrentPassphrase, R.string.title_change_passphrase); setPassphraseDialog.show(getActivity().getSupportFragmentManager(), "setPassphraseDialog"); } @@ -350,29 +354,28 @@ public class EditKeyFragment extends LoaderFragment implements mSubkeysAddedAdapter.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.SIGN_DATA, null)); } - private void save() { - String passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), + private void cachePassphraseForEdit() { + mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), mSaveKeyringParcel.mMasterKeyId); - if (passphrase == null) { + if (mCurrentPassphrase == null) { PassphraseDialogFragment.show(getActivity(), mSaveKeyringParcel.mMasterKeyId, new Handler() { @Override public void handleMessage(Message message) { if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - String passphrase = + mCurrentPassphrase = message.getData().getString(PassphraseDialogFragment.MESSAGE_DATA_PASSPHRASE); Log.d(Constants.TAG, "after caching passphrase"); - saveFinal(passphrase); + } else { + EditKeyFragment.this.getActivity().finish(); } } } ); - } else { - saveFinal(passphrase); } } - private void saveFinal(String passphrase) { + private void save(String passphrase) { Log.d(Constants.TAG, "add userids to parcel: " + mUserIdsAddedAdapter.getDataAsStringList()); mSaveKeyringParcel.addUserIds = mUserIdsAddedAdapter.getDataAsStringList(); 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 04bec3282..0fe5fdeda 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 @@ -26,12 +26,15 @@ import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.support.v4.app.DialogFragment; +import android.text.TextUtils; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager.LayoutParams; import android.view.inputmethod.EditorInfo; import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; @@ -44,6 +47,7 @@ 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 = "title"; public static final int MESSAGE_OKAY = 1; @@ -52,6 +56,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi private Messenger mMessenger; private EditText mPassphraseEditText; private EditText mPassphraseAgainEditText; + private CheckBox mNoPassphraseCheckBox; /** * Creates new instance of this dialog fragment @@ -60,11 +65,12 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi * @param messenger to communicate back after setting the passphrase * @return */ - public static SetPassphraseDialogFragment newInstance(Messenger messenger, int title) { + public static SetPassphraseDialogFragment newInstance(Messenger messenger, String oldPassphrase, 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); @@ -80,6 +86,7 @@ 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); @@ -92,6 +99,19 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase); 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); + } + + mNoPassphraseCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + mPassphraseEditText.setEnabled(!isChecked); + mPassphraseAgainEditText.setEnabled(!isChecked); + } + }); alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @@ -99,24 +119,31 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi public void onClick(DialogInterface dialog, int id) { dismiss(); - String passphrase1 = mPassphraseEditText.getText().toString(); - String passphrase2 = mPassphraseAgainEditText.getText().toString(); - if (!passphrase1.equals(passphrase2)) { - Toast.makeText( - activity, - getString(R.string.error_message, - getString(R.string.passphrases_do_not_match)), Toast.LENGTH_SHORT) - .show(); - return; - } - - if (passphrase1.equals("")) { - Toast.makeText( - activity, - getString(R.string.error_message, - getString(R.string.passphrase_must_not_be_empty)), - Toast.LENGTH_SHORT).show(); - return; + String passphrase1; + if (mNoPassphraseCheckBox.isChecked()) { + passphrase1 = ""; + } else { + passphrase1 = mPassphraseEditText.getText().toString(); + String passphrase2 = mPassphraseAgainEditText.getText().toString(); + if (!passphrase1.equals(passphrase2)) { + Toast.makeText( + activity, + getString(R.string.error_message, + getString(R.string.passphrases_do_not_match)), Toast.LENGTH_SHORT + ) + .show(); + return; + } + + if (passphrase1.equals("")) { + Toast.makeText( + activity, + getString(R.string.error_message, + getString(R.string.passphrase_must_not_be_empty)), + Toast.LENGTH_SHORT + ).show(); + return; + } } // return resulting data back to activity diff --git a/OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml b/OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml index f52d693e0..856bef36a 100644 --- a/OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml +++ b/OpenKeychain/src/main/res/layout/edit_key_subkey_added_item.xml @@ -18,6 +18,89 @@ android:paddingLeft="8dp" android:stretchColumns="1"> + + + + +