From 2571d25058706ae2725e0a70db4fa1c7eacfc153 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Wed, 22 Apr 2015 06:15:14 +0530 Subject: keyserver verification on addition --- .../keychain/ui/SettingsKeyServerActivity.java | 60 +++- .../ui/dialog/AddKeyserverDialogFragment.java | 320 +++++++++++++++++++++ .../src/main/res/layout/add_keyserver_dialog.xml | 29 ++ OpenKeychain/src/main/res/values/strings.xml | 12 + 4 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java create mode 100644 OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java index 9f2e46b38..8f025c769 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java @@ -20,6 +20,9 @@ package org.sufficientlysecure.keychain.ui; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -28,6 +31,8 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.base.BaseActivity; +import org.sufficientlysecure.keychain.ui.dialog.AddKeyserverDialogFragment; +import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.widget.Editor; import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; import org.sufficientlysecure.keychain.ui.widget.KeyServerEditor; @@ -95,7 +100,7 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi Intent intent = getIntent(); String servers[] = intent.getStringArrayExtra(EXTRA_KEY_SERVERS); makeServerList(servers); - } + } @Override protected void initLayout() { @@ -124,10 +129,63 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi } + // button to add keyserver clicked public void onClick(View v) { + Handler returnHandler = new Handler() { + @Override + public void handleMessage(Message message) { + Bundle data = message.getData(); + switch (message.what) { + case AddKeyserverDialogFragment.MESSAGE_OKAY: { + boolean verified = data.getBoolean(AddKeyserverDialogFragment.MESSAGE_VERIFIED); + if (verified) { + Notify.create(SettingsKeyServerActivity.this, + R.string.add_keyserver_verified, Notify.Style.OK).show(); + } else { + Notify.create(SettingsKeyServerActivity.this, + R.string.add_keyserver_without_verification, + Notify.Style.WARN).show(); + } + String keyserver = data.getString(AddKeyserverDialogFragment.MESSAGE_KEYSERVER); + addKeyserver(keyserver); + break; + } + case AddKeyserverDialogFragment.MESSAGE_VERIFICATION_FAILED: { + AddKeyserverDialogFragment.FailureReason failureReason = + (AddKeyserverDialogFragment.FailureReason) data.getSerializable( + AddKeyserverDialogFragment.MESSAGE_FAILURE_REASON); + switch (failureReason) { + case CONNECTION_FAILED: { + Notify.create(SettingsKeyServerActivity.this, + R.string.add_keyserver_connection_failed, + Notify.Style.ERROR).show(); + break; + } + case INVALID_URL: { + Notify.create(SettingsKeyServerActivity.this, + R.string.add_keyserver_invalid_url, + Notify.Style.ERROR).show(); + break; + } + } + break; + } + } + } + }; + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(returnHandler); + AddKeyserverDialogFragment dialogFragment = AddKeyserverDialogFragment + .newInstance(messenger, R.string.add_keyserver_dialog_title); + dialogFragment.show(getSupportFragmentManager(), "addKeyserverDialog"); + } + + public void addKeyserver(String keyserverUrl) { KeyServerEditor view = (KeyServerEditor) mInflater.inflate(R.layout.key_server_editor, mEditors, false); view.setEditorListener(this); + view.setValue(keyserverUrl); mEditors.addView(view); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java new file mode 100644 index 000000000..cbef5950f --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddKeyserverDialogFragment.java @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2012-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.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.support.v4.app.DialogFragment; +import android.test.suitebuilder.TestSuiteBuilder; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.TlsHelper; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +import javax.net.ssl.HttpsURLConnection; + +public class AddKeyserverDialogFragment extends DialogFragment implements OnEditorActionListener { + private static final String ARG_MESSENGER = "messenger"; + private static final String ARG_TITLE = "title"; + + public static final int MESSAGE_OKAY = 1; + public static final int MESSAGE_VERIFICATION_FAILED = 2; + + public static final String MESSAGE_KEYSERVER = "new_keyserver"; + public static final String MESSAGE_VERIFIED = "verified"; + public static final String MESSAGE_FAILURE_REASON = "failure_reason"; + + private Messenger mMessenger; + private EditText mKeyserverEditText; + private CheckBox mVerifyKeyserverCheckBox; + + public static enum FailureReason { + INVALID_URL, + CONNECTION_FAILED + } + + ; + + /** + * Creates new instance of this dialog fragment + * + * @param title title of dialog + * @param messenger to communicate back after setting the passphrase + * @return + */ + public static AddKeyserverDialogFragment newInstance(Messenger messenger, int title) { + AddKeyserverDialogFragment frag = new AddKeyserverDialogFragment(); + Bundle args = new Bundle(); + args.putInt(ARG_TITLE, title); + args.putParcelable(ARG_MESSENGER, messenger); + + frag.setArguments(args); + + return frag; + } + + /** + * Creates dialog + */ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Activity activity = getActivity(); + + int title = getArguments().getInt(ARG_TITLE); + mMessenger = getArguments().getParcelable(ARG_MESSENGER); + + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); + + alert.setTitle(title); + + LayoutInflater inflater = activity.getLayoutInflater(); + View view = inflater.inflate(R.layout.add_keyserver_dialog, null); + alert.setView(view); + + mKeyserverEditText = (EditText) view.findViewById(R.id.keyserver_url_edit_text); + mVerifyKeyserverCheckBox = (CheckBox) view.findViewById(R.id.verify_keyserver_checkbox); + + // we don't want dialog to be dismissed on click, thereby requiring the hack seen below + // and in onStart + alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + // we need to have an empty listener to prevent errors on some devices as mentioned + // at http://stackoverflow.com/q/13746412/3000919 + // actual listener set in onStart + } + }); + + alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int id) { + dismiss(); + } + }); + + // Hack to open keyboard. + // This is the only method that I found to work across all Android versions + // http://turbomanage.wordpress.com/2012/05/02/show-soft-keyboard-automatically-when-edittext-receives-focus/ + // Notes: * onCreateView can't be used because we want to add buttons to the dialog + // * opening in onActivityCreated does not work on Android 4.4 + mKeyserverEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + mKeyserverEditText.post(new Runnable() { + @Override + public void run() { + InputMethodManager imm = (InputMethodManager) getActivity() + .getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(mKeyserverEditText, InputMethodManager.SHOW_IMPLICIT); + } + }); + } + }); + mKeyserverEditText.requestFocus(); + + mKeyserverEditText.setImeActionLabel(getString(android.R.string.ok), + EditorInfo.IME_ACTION_DONE); + mKeyserverEditText.setOnEditorActionListener(this); + + return alert.show(); + } + + @Override + public void onStart() { + super.onStart(); + AlertDialog addKeyserverDialog = (AlertDialog) getDialog(); + if (addKeyserverDialog != null) { + Button positiveButton = addKeyserverDialog.getButton(Dialog.BUTTON_POSITIVE); + positiveButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String keyserverUrl = mKeyserverEditText.getText().toString(); + if (mVerifyKeyserverCheckBox.isChecked()) { + verifyConnection(keyserverUrl); + } else { + dismiss(); + // return unverified keyserver back to activity + addKeyserver(keyserverUrl, false); + } + } + }); + } + } + + public void addKeyserver(String keyserver, boolean verified) { + dismiss(); + Bundle data = new Bundle(); + data.putString(MESSAGE_KEYSERVER, keyserver); + data.putBoolean(MESSAGE_VERIFIED, verified); + + sendMessageToHandler(MESSAGE_OKAY, data); + } + + public void verificationFailed(FailureReason reason) { + Bundle data = new Bundle(); + data.putSerializable(MESSAGE_FAILURE_REASON, reason); + + sendMessageToHandler(MESSAGE_VERIFICATION_FAILED, data); + } + + public void verifyConnection(String keyserver) { + + new AsyncTask() { + ProgressDialog mProgressDialog; + String mKeyserver; + + @Override + protected void onPreExecute() { + mProgressDialog = new ProgressDialog(getActivity()); + mProgressDialog.setMessage(getString(R.string.progress_verifying_keyserver_url)); + mProgressDialog.setCancelable(false); + mProgressDialog.show(); + } + + @Override + protected FailureReason doInBackground(String... keyservers) { + mKeyserver = keyservers[0]; + FailureReason reason = null; + try { + // replace hkps/hkp scheme and reconstruct Uri + Uri keyserverUri = Uri.parse(mKeyserver); + String scheme = keyserverUri.getScheme(); + String schemeSpecificPart = keyserverUri.getSchemeSpecificPart(); + String fragment = keyserverUri.getFragment(); + if (scheme == null) throw new MalformedURLException(); + if (scheme.equalsIgnoreCase("hkps")) scheme = "https"; + else if (scheme.equalsIgnoreCase("hkp")) scheme = "http"; + URI newKeyserver = new URI(scheme, schemeSpecificPart, fragment); + + Log.d("Converted URL", newKeyserver.toString()); + TlsHelper.openConnection(newKeyserver.toURL()).getInputStream(); + } catch (TlsHelper.TlsHelperException e) { + reason = FailureReason.CONNECTION_FAILED; + } catch (MalformedURLException e) { + Log.w(Constants.TAG, "Invalid keyserver URL entered by user."); + reason = FailureReason.INVALID_URL; + } catch (URISyntaxException e) { + Log.w(Constants.TAG, "Invalid keyserver URL entered by user."); + reason = FailureReason.INVALID_URL; + } catch (IOException e) { + Log.w(Constants.TAG, "Could not connect to entered keyserver url"); + reason = FailureReason.CONNECTION_FAILED; + } + return reason; + } + + @Override + protected void onPostExecute(FailureReason failureReason) { + mProgressDialog.dismiss(); + if (failureReason == null) { + addKeyserver(mKeyserver, true); + } else { + verificationFailed(failureReason); + } + } + }.execute(keyserver); + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + + // hide keyboard on dismiss + hideKeyboard(); + } + + private void hideKeyboard() { + if (getActivity() == null) { + return; + } + InputMethodManager inputManager = (InputMethodManager) getActivity() + .getSystemService(Context.INPUT_METHOD_SERVICE); + + //check if no view has focus: + View v = getActivity().getCurrentFocus(); + if (v == null) + return; + + inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0); + } + + /** + * Associate the "done" button on the soft keyboard with the okay button in the view + */ + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (EditorInfo.IME_ACTION_DONE == actionId) { + AlertDialog dialog = ((AlertDialog) getDialog()); + Button bt = dialog.getButton(AlertDialog.BUTTON_POSITIVE); + + bt.performClick(); + return true; + } + return false; + } + + /** + * 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_keyserver_dialog.xml b/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml new file mode 100644 index 000000000..78e9247ea --- /dev/null +++ b/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index d4c67aa23..fa8bd16b9 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -86,6 +86,7 @@ "Encrypt text" "Add additional email address" "Unlock" + "Add" "Settings" @@ -152,6 +153,8 @@ "Enable compression" "Encrypt filenames" "Hide recipients" + "Verify Keyserver" + "Enter Keyserver URL" "Search Keyserver" "Search HKP keyserver" @@ -353,6 +356,8 @@ "consolidate: saving to cache…" "consolidate: reimporting…" + "verifying keyserver…" + "Search via Name, Email…" @@ -645,6 +650,13 @@ "<none>" + + "Add Keyserver" + "Keyserver verified!" + "Keyserver added without verification." + "Invalid URL!" + "Failed to connect to keyserver. Please check the URL and your internet connection." + "Keys" "Encrypt/Decrypt" -- cgit v1.2.3 From aecebd2ac012804477ab3ec59ca6cf0417a56c5f Mon Sep 17 00:00:00 2001 From: Manoj Khanna Date: Wed, 22 Apr 2015 18:30:35 +0530 Subject: Fixed Snackbar behind layout Surrounded string with quotes --- .../keychain/ui/EncryptFilesFragment.java | 14 +++++------ .../keychain/ui/EncryptTextFragment.java | 12 +++++----- .../src/main/res/layout/encrypt_files_fragment.xml | 4 ++-- .../src/main/res/layout/encrypt_text_fragment.xml | 27 +++++++++++----------- OpenKeychain/src/main/res/values/strings.xml | 1 + 5 files changed, 29 insertions(+), 29 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index ccb4a6355..458810541 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -202,7 +202,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { } catch (IOException e) { Notify.create(getActivity(), getActivity().getString(R.string.error_file_added_already, FileHelper.getFilename(getActivity(), inputUri)), - Notify.Style.ERROR).show(); + Notify.Style.ERROR).show(this); return; } mSelectedFiles.requestFocus(); @@ -230,7 +230,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { private void encryptClicked(boolean share) { if (mFilesModels.isEmpty()) { Notify.create(getActivity(), R.string.error_no_file_selected, - Notify.Style.ERROR).show(); + Notify.Style.ERROR).show(this); return; } if (share) { @@ -247,7 +247,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { } else { if (mFilesModels.size() > 1) { Notify.create(getActivity(), R.string.error_multi_not_supported, - Notify.Style.ERROR).show(); + Notify.Style.ERROR).show(this); return; } showOutputFileDialog(); @@ -330,7 +330,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { if (mFilesModels.isEmpty()) { Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR) - .show(); + .show(this); return false; } else if (mFilesModels.size() > 1 && !mShareAfterEncrypt) { Log.e(Constants.TAG, "Aborting: mInputUris.size() > 1 && !mShareAfterEncrypt"); @@ -347,12 +347,12 @@ public class EncryptFilesFragment extends CryptoOperationFragment { if (mPassphrase == null) { Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR) - .show(); + .show(this); return false; } if (mPassphrase.isEmpty()) { Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) - .show(); + .show(this); return false; } @@ -365,7 +365,7 @@ public class EncryptFilesFragment extends CryptoOperationFragment { // Files must be encrypted, only text can be signed-only right now if (!gotEncryptionKeys) { Notify.create(getActivity(), R.string.select_encryption_key, Notify.Style.ERROR) - .show(); + .show(this); return false; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java index b37a2ca79..3f9147cc4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java @@ -288,9 +288,9 @@ public class EncryptTextFragment extends CryptoOperationFragment { } protected boolean inputIsValid() { - if (mMessage == null) { - Notify.create(getActivity(), R.string.error_message, Notify.Style.ERROR) - .show(); + if (mMessage == null || mMessage.isEmpty()) { + Notify.create(getActivity(), R.string.error_empty_text, Notify.Style.ERROR) + .show(this); return false; } @@ -299,12 +299,12 @@ public class EncryptTextFragment extends CryptoOperationFragment { if (mSymmetricPassphrase == null) { Notify.create(getActivity(), R.string.passphrases_do_not_match, Notify.Style.ERROR) - .show(); + .show(this); return false; } if (mSymmetricPassphrase.isEmpty()) { Notify.create(getActivity(), R.string.passphrase_must_not_be_empty, Notify.Style.ERROR) - .show(); + .show(this); return false; } @@ -316,7 +316,7 @@ public class EncryptTextFragment extends CryptoOperationFragment { if (!gotEncryptionKeys && mSigningKeyId == 0) { Notify.create(getActivity(), R.string.select_encryption_or_signature_key, Notify.Style.ERROR) - .show(); + .show(this); return false; } } diff --git a/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml index b75ec5022..8fd2c79fc 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_files_fragment.xml @@ -1,5 +1,5 @@ - @@ -12,4 +12,4 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - \ No newline at end of file + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml index 3c21291cd..7645918f4 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_text_fragment.xml @@ -1,25 +1,24 @@ - + android:layout_height="match_parent"> - + android:layout_height="match_parent" + android:fillViewport="true"> + android:hint="@string/encrypt_content_edit_text_hint" /> - - + + + diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index fa8bd16b9..df88336a1 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1238,6 +1238,7 @@ "Swipe down to update from keyserver" "Select at least one file to encrypt!" "Saving of multiple files not supported. This is a limitation on current Android." + "Type some text to encrypt!" "Key:" "To start a key exchange, choose the number of participants on the right side, then hit the “Start exchange” button.\n\nYou will be asked two more questions to make sure only the right participants are in the exchange and their fingerprints are correct." "Start exchange" -- cgit v1.2.3