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(-) 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 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(-) 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(+) 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 858be93f3d4538d2e4e69353a5043ed3273e9e76 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 2 Jul 2014 15:02:11 +0200 Subject: update spongycastle to include addSubkeyBindingCertification --- extern/spongycastle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/spongycastle b/extern/spongycastle index 09d85b7d7..968405ee5 160000 --- a/extern/spongycastle +++ b/extern/spongycastle @@ -1 +1 @@ -Subproject commit 09d85b7d7a64b3003210d065c4210ff7fb7a8c6d +Subproject commit 968405ee5d4272330cffdf75f7eee4cd9f5c8646 -- 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(-) 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(-) 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 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 bb39caa28d5138adaf936fbfe18d8db05f5de31c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 2 Jul 2014 15:11:06 +0200 Subject: Add infographic from FSFE --- Resources/gnupg-infographic/README | 13 + Resources/gnupg-infographic/gnupg-infographic.png | Bin 0 -> 486199 bytes Resources/gnupg-infographic/gnupg-infographic.svg | 8145 +++++++++++++++++++++ 3 files changed, 8158 insertions(+) create mode 100644 Resources/gnupg-infographic/README create mode 100644 Resources/gnupg-infographic/gnupg-infographic.png create mode 100644 Resources/gnupg-infographic/gnupg-infographic.svg diff --git a/Resources/gnupg-infographic/README b/Resources/gnupg-infographic/README new file mode 100644 index 000000000..f29c0a84a --- /dev/null +++ b/Resources/gnupg-infographic/README @@ -0,0 +1,13 @@ +Source files for GnuPG infographic +================================== + +These are the source graphics for the Email Self-Defense infographic from the +Free Software Foundation, available at . + +License +------- + +Copyright (c) 2014 Free Software Foundation, Inc. + +Licensed under the Creative Commons Attribution license (CC-BY). See full +source and attribution text at the above site. diff --git a/Resources/gnupg-infographic/gnupg-infographic.png b/Resources/gnupg-infographic/gnupg-infographic.png new file mode 100644 index 000000000..52b8f21ac Binary files /dev/null and b/Resources/gnupg-infographic/gnupg-infographic.png differ diff --git a/Resources/gnupg-infographic/gnupg-infographic.svg b/Resources/gnupg-infographic/gnupg-infographic.svg new file mode 100644 index 000000000..9a17421e2 --- /dev/null +++ b/Resources/gnupg-infographic/gnupg-infographic.svg @@ -0,0 +1,8145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + To protect ourselves from surveillance, we need to learn when to use GnuPG and startsharing our public keys whenever we share email addresses. + + + Thousands of people already use GnuPG, including activists, journalists, whistleblowers and everyday folks. Each person using it makes our community stronger, and shows surveillance agencies that we are ready to fight back. + + + + + + + + + + + GnuPG is freely licensed software; it's completely transparent and anyone can copy it or make their own version. This makes it safer from surveillance than proprietary software (like Windows or Word). Learn more at FSF.org. + + + Teach yourself email self-defense. Learn GnuPG in 30 minutes at EmailSelfDefense.FSF.org + + + + + + + + + + + + + + + + + + + + + + PUBLIC PRIVATE YOUR PUBLIC KEY YOUR PRIVATE KEY + + + All you need is a simple program called GnuPG. It encrypts your email into a code that only the right people can read. GnuPG runs on pretty much any computer or smartphone. It's freely licensed and costs no money. Each user has a unique public key and private key, which are random strings of numbers. Take back your privacy! Meet GnuPG Your public key isn't like a physical key, because it's shared. It's in an online directory, where people can look it up and download it. People use your public key, along with GnuPG, to encrypt emails they send to you. Your private key is more like a physical key, because you keep it to yourself (on your computer). You use GnuPG and your private key to decode encrypted emails other people send to you. If an email encrypted with GnuPG falls into the wrong hands, it'll just look like nonsense. Without the real recipient's private key, it's almost impossible to read it. To the real recipient, it opens up like a normal email. Easy! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The password protecting your email is only a thin layer of security that can't protect against the battering ram of sophisticated surveillance systems. Each message passes through many computer systems on the way to its destination. Surveillance agencies take advantage of this to read millions and millions of emails. Even if you have nothing to hide, when you send normal email, the people you talk to are being exposed as well. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ? ? ? ? + + + + + + + + + + + + + + + + + + + + ERROR + + + %#&$! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + EMAIL SELF-DEFENSE Bulk surveillance violates our fundamental rights and makes free speech risky. But we're far from helpless to do something about it. + + + + + + + + + PUB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PRIV + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ? ? ? ? + The sender and recipient are both safer now. Even if this email doesn't have any private information, being encrypted makes it gum up bulk surveillance systems. Take that, surveillance! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GnuPG + + + + Infographic and guide design by Journalism++ + + + + + Copyright 2014 Free Software Foundation. Remixing encouraged! Get the source at the URL above. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 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(-) 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(-) 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(-) 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(-) 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 931bfdd9df42a4f1ecd9c9384d83fc2c269645dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 2 Jul 2014 16:56:38 +0200 Subject: Update spongycastle --- extern/spongycastle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/spongycastle b/extern/spongycastle index 09d85b7d7..968405ee5 160000 --- a/extern/spongycastle +++ b/extern/spongycastle @@ -1 +1 @@ -Subproject commit 09d85b7d7a64b3003210d065c4210ff7fb7a8c6d +Subproject commit 968405ee5d4272330cffdf75f7eee4cd9f5c8646 -- 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(-) 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(-) 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(-) 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(-) 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 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(+) 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(+) 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(-) 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"> + + + + +