diff options
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain')
133 files changed, 0 insertions, 26804 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java deleted file mode 100644 index b3bfaa229..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain; - -import android.os.Environment; - -import org.spongycastle.jce.provider.BouncyCastleProvider; -import org.sufficientlysecure.keychain.remote.ui.AppsListActivity; -import org.sufficientlysecure.keychain.ui.DecryptActivity; -import org.sufficientlysecure.keychain.ui.EncryptActivity; -import org.sufficientlysecure.keychain.ui.ImportKeysActivity; -import org.sufficientlysecure.keychain.ui.KeyListActivity; - -public final class Constants { - - public static final boolean DEBUG = BuildConfig.DEBUG; - - public static final String TAG = "Keychain"; - - public static final String PACKAGE_NAME = "org.sufficientlysecure.keychain"; - - // as defined in http://tools.ietf.org/html/rfc3156, section 7 - public static final String NFC_MIME = "application/pgp-keys"; - - // used by QR Codes (Guardian Project, Monkeysphere compatiblity) - public static final String FINGERPRINT_SCHEME = "openpgp4fpr"; - - // Not BC due to the use of Spongy Castle for Android - public static final String SC = BouncyCastleProvider.PROVIDER_NAME; - public static final String BOUNCY_CASTLE_PROVIDER_NAME = SC; - - public static final String INTENT_PREFIX = PACKAGE_NAME + ".action."; - - public static final class Path { - public static final String APP_DIR = Environment.getExternalStorageDirectory() - + "/OpenKeychain"; - public static final String APP_DIR_FILE = APP_DIR + "/export.asc"; - } - - public static final class Pref { - public static final String DEFAULT_ENCRYPTION_ALGORITHM = "defaultEncryptionAlgorithm"; - public static final String DEFAULT_HASH_ALGORITHM = "defaultHashAlgorithm"; - public static final String DEFAULT_ASCII_ARMOR = "defaultAsciiArmor"; - public static final String DEFAULT_MESSAGE_COMPRESSION = "defaultMessageCompression"; - public static final String DEFAULT_FILE_COMPRESSION = "defaultFileCompression"; - public static final String PASSPHRASE_CACHE_TTL = "passphraseCacheTtl"; - public static final String LANGUAGE = "language"; - public static final String FORCE_V3_SIGNATURES = "forceV3Signatures"; - public static final String KEY_SERVERS = "keyServers"; - } - - public static final class Defaults { - public static final String KEY_SERVERS = "pool.sks-keyservers.net, subkeys.pgp.net, pgp.mit.edu"; - } - - public static final class DrawerItems { - public static final Class KEY_LIST = KeyListActivity.class; - public static final Class ENCRYPT = EncryptActivity.class; - public static final Class DECRYPT = DecryptActivity.class; - public static final Class REGISTERED_APPS_LIST = AppsListActivity.class; - public static final Class[] ARRAY = new Class[]{ - KEY_LIST, - ENCRYPT, - DECRYPT, - REGISTERED_APPS_LIST - }; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java deleted file mode 100644 index 784ec340e..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain; - -import org.spongycastle.bcpg.CompressionAlgorithmTags; - -/** - * - * TODO: - * - * - refactor ids, some are not needed and can be done with xml - * - */ -public final class Id { - - public static final class menu { - - public static final class option { - public static final int new_passphrase = 0x21070001; - public static final int create = 0x21070002; - public static final int about = 0x21070003; - public static final int manage_public_keys = 0x21070004; - public static final int manage_secret_keys = 0x21070005; - public static final int export_keys = 0x21070007; - public static final int preferences = 0x21070008; - public static final int search = 0x21070009; - public static final int help = 0x21070010; - public static final int key_server = 0x21070011; - public static final int scanQRCode = 0x21070012; - public static final int encrypt = 0x21070013; - public static final int encrypt_to_clipboard = 0x21070014; - public static final int decrypt = 0x21070015; - public static final int reply = 0x21070016; - public static final int cancel = 0x21070017; - public static final int save = 0x21070018; - public static final int okay = 0x21070019; - public static final int import_from_file = 0x21070020; - public static final int import_from_qr_code = 0x21070021; - public static final int import_from_nfc = 0x21070022; - public static final int crypto_consumers = 0x21070023; - public static final int createExpert = 0x21070024; - } - } - - // use only lower 16 bits due to compatibility lib - public static final class message { - public static final int progress_update = 0x00006001; - public static final int done = 0x00006002; - public static final int import_keys = 0x00006003; - public static final int export_keys = 0x00006004; - public static final int import_done = 0x00006005; - public static final int export_done = 0x00006006; - public static final int create_key = 0x00006007; - public static final int edit_key = 0x00006008; - public static final int delete_done = 0x00006009; - public static final int query_done = 0x00006010; - public static final int unknown_signature_key = 0x00006011; - } - - // use only lower 16 bits due to compatibility lib - public static final class request { - public static final int public_keys = 0x00007001; - public static final int secret_keys = 0x00007002; - public static final int filename = 0x00007003; -// public static final int output_filename = 0x00007004; - public static final int key_server_preference = 0x00007005; -// public static final int look_up_key_id = 0x00007006; - public static final int export_to_server = 0x00007007; - public static final int import_from_qr_code = 0x00007008; - public static final int sign_key = 0x00007009; - } - - public static final class dialog { - public static final int passphrase = 0x21070001; - public static final int encrypting = 0x21070002; - public static final int decrypting = 0x21070003; - public static final int new_passphrase = 0x21070004; - public static final int passphrases_do_not_match = 0x21070005; - public static final int no_passphrase = 0x21070006; - public static final int saving = 0x21070007; - public static final int delete_key = 0x21070008; - public static final int import_keys = 0x21070009; - public static final int importing = 0x2107000a; - public static final int export_key = 0x2107000b; - public static final int export_keys = 0x2107000c; - public static final int exporting = 0x2107000d; - public static final int new_account = 0x2107000e; - public static final int change_log = 0x21070010; - public static final int output_filename = 0x21070011; - public static final int delete_file = 0x21070012; - public static final int deleting = 0x21070013; - public static final int help = 0x21070014; - public static final int querying = 0x21070015; - public static final int lookup_unknown_key = 0x21070016; - public static final int signing = 0x21070017; - } - - public static final class task { - public static final int import_keys = 0x21070001; - public static final int export_keys = 0x21070002; - } - - public static final class type { - public static final int public_key = 0x21070001; - public static final int secret_key = 0x21070002; - public static final int user_id = 0x21070003; - public static final int key = 0x21070004; - public static final int public_secret_key = 0x21070005; - } - - public static final class choice { - public static final class algorithm { - public static final int dsa = 0x21070001; - public static final int elgamal = 0x21070002; - public static final int rsa = 0x21070003; - } - - public static final class compression { - public static final int none = 0x21070001; - public static final int zlib = CompressionAlgorithmTags.ZLIB; - public static final int bzip2 = CompressionAlgorithmTags.BZIP2; - public static final int zip = CompressionAlgorithmTags.ZIP; - } - - public static final class usage { - public static final int sign_only = 0x21070001; - public static final int encrypt_only = 0x21070002; - public static final int sign_and_encrypt = 0x21070003; - } - - public static final class action { - public static final int encrypt = 0x21070001; - public static final int decrypt = 0x21070002; - public static final int import_public = 0x21070003; - public static final int import_secret = 0x21070004; - } - } - - public static final class return_value { - public static final int ok = 0; - public static final int error = -1; - public static final int no_master_key = -2; - public static final int updated = 1; - public static final int bad = -3; - } - - public static final class target { - public static final int clipboard = 0x21070001; - public static final int email = 0x21070002; - public static final int file = 0x21070003; - public static final int message = 0x21070004; - } - - public static final class mode { - public static final int undefined = 0x21070001; - public static final int byte_array = 0x21070002; - public static final int file = 0x21070003; - public static final int stream = 0x21070004; - } - - public static final class key { - public static final int none = 0; - public static final int symmetric = -1; - } - - public static final class content { - public static final int unknown = 0; - public static final int encrypted_data = 1; - public static final int keys = 2; - } - - public static final class keyserver { - public static final int search = 0x21070001; - public static final int get = 0x21070002; - public static final int add = 0x21070003; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java deleted file mode 100644 index 9b80e76f3..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain; - -import android.app.Application; -import android.os.Environment; - -import org.spongycastle.jce.provider.BouncyCastleProvider; - -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.PRNGFixes; - -import java.io.File; -import java.security.Provider; -import java.security.Security; - -public class KeychainApplication extends Application { - - /** - * Called when the application is starting, before any activity, service, or receiver objects - * (excluding content providers) have been created. - */ - @Override - public void onCreate() { - super.onCreate(); - - /* - * Sets Bouncy (Spongy) Castle as preferred security provider - * - * insertProviderAt() position starts from 1 - */ - Security.insertProviderAt(new BouncyCastleProvider(), 1); - - /* - * apply RNG fixes - * - * among other things, executes Security.insertProviderAt(new - * LinuxPRNGSecureRandomProvider(), 1) for Android <= SDK 17 - */ - PRNGFixes.apply(); - Log.d(Constants.TAG, "Bouncy Castle set and PRNG Fixes applied!"); - - if (Constants.DEBUG) { - Provider[] providers = Security.getProviders(); - Log.d(Constants.TAG, "Installed Security Providers:"); - for (Provider p : providers) { - Log.d(Constants.TAG, "provider class: " + p.getClass().getName()); - } - } - - // Create APG directory on sdcard if not existing - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - File dir = new File(Constants.Path.APP_DIR); - if (!dir.exists() && !dir.mkdirs()) { - // ignore this for now, it's not crucial - // that the directory doesn't exist at this point - } - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java deleted file mode 100644 index 1cac5762d..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.compatibility; - -import android.content.Context; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.Log; - -import java.lang.reflect.Method; - -public class ClipboardReflection { - - private static final String clipboardLabel = "Keychain"; - - /** - * Wrapper around ClipboardManager based on Android version using Reflection API - * - * @param context - * @param text - */ - public static void copyToClipboard(Context context, String text) { - Object clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE); - try { - if ("android.text.ClipboardManager".equals(clipboard.getClass().getName())) { - Method methodSetText = clipboard.getClass() - .getMethod("setText", CharSequence.class); - methodSetText.invoke(clipboard, text); - } else if ("android.content.ClipboardManager".equals(clipboard.getClass().getName())) { - Class<?> classClipData = Class.forName("android.content.ClipData"); - Method methodNewPlainText = classClipData.getMethod("newPlainText", - CharSequence.class, CharSequence.class); - Object clip = methodNewPlainText.invoke(null, clipboardLabel, text); - methodNewPlainText = clipboard.getClass() - .getMethod("setPrimaryClip", classClipData); - methodNewPlainText.invoke(clipboard, clip); - } - } catch (Exception e) { - Log.e(Constants.TAG, "There was an error copying the text to the clipboard", e); - } - } - - /** - * Wrapper around ClipboardManager based on Android version using Reflection API - * - * @param context - */ - public static CharSequence getClipboardText(Context context) { - Object clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE); - try { - if ("android.text.ClipboardManager".equals(clipboard.getClass().getName())) { - // CharSequence text = clipboard.getText(); - Method methodGetText = clipboard.getClass().getMethod("getText"); - Object text = methodGetText.invoke(clipboard); - - return (CharSequence) text; - } else if ("android.content.ClipboardManager".equals(clipboard.getClass().getName())) { - // ClipData clipData = clipboard.getPrimaryClip(); - Method methodGetPrimaryClip = clipboard.getClass().getMethod("getPrimaryClip"); - Object clipData = methodGetPrimaryClip.invoke(clipboard); - - // ClipData.Item clipDataItem = clipData.getItemAt(0); - Method methodGetItemAt = clipData.getClass().getMethod("getItemAt", int.class); - Object clipDataItem = methodGetItemAt.invoke(clipData, 0); - - // CharSequence text = clipDataItem.coerceToText(context); - Method methodGetString = clipDataItem.getClass().getMethod("coerceToText", - Context.class); - Object text = methodGetString.invoke(clipDataItem, context); - - return (CharSequence) text; - } else { - return null; - } - } catch (Exception e) { - Log.e(Constants.TAG, "There was an error getting the text from the clipboard", e); - return null; - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java deleted file mode 100644 index 36f7fd23b..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.compatibility; - -import android.os.Build; -import android.os.Handler; - -/** - * Bug on Android >= 4.2 - * - * http://code.google.com/p/android/issues/detail?id=41901 - * - * DialogFragment disappears on pressing home and comming back. This also happens especially in - * FileDialogFragment after launching a file manager and coming back. - * - * Usage: <code> - * DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { - * public void run() { - * // show dialog... - * } - * }); - * </code> - */ -public class DialogFragmentWorkaround { - public static final SDKLevel17Interface INTERFACE = - ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) ? new SDKLevel17Impl() - : new SDKLevelPriorLevel17Impl()); - - private static final int RUNNABLE_DELAY = 300; - - public interface SDKLevel17Interface { - // Workaround for http://code.google.com/p/android/issues/detail?id=41901 - void runnableRunDelayed(Runnable runnable); - } - - private static class SDKLevelPriorLevel17Impl implements SDKLevel17Interface { - @Override - public void runnableRunDelayed(Runnable runnable) { - runnable.run(); - } - } - - private static class SDKLevel17Impl implements SDKLevel17Interface { - @Override - public void runnableRunDelayed(Runnable runnable) { - new Handler().postDelayed(runnable, RUNNABLE_DELAY); - } - } - - // Can't instantiate this class - private DialogFragmentWorkaround() { - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ListFragmentWorkaround.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ListFragmentWorkaround.java deleted file mode 100644 index 1cb91c688..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ListFragmentWorkaround.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.compatibility; - -import android.support.v4.app.ListFragment; -import android.view.View; -import android.widget.ListView; - -/** - * Bug on Android >= 4.1 - * <p/> - * http://code.google.com/p/android/issues/detail?id=35885 - * <p/> - * Items are not checked in layout - */ -public class ListFragmentWorkaround extends ListFragment { - - @Override - public void onListItemClick(ListView l, View v, int position, long id) { - l.setItemChecked(position, l.isItemChecked(position)); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java deleted file mode 100644 index a26df556d..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ActionBarHelper.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.helper; - -import android.app.Activity; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.TextView; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Log; - -public class ActionBarHelper { - - /** - * Set actionbar without home button if called from another app - * - * @param activity - */ - public static void setBackButton(ActionBarActivity activity) { - final ActionBar actionBar = activity.getSupportActionBar(); - Log.d(Constants.TAG, "calling package (only set when using startActivityForResult)=" - + activity.getCallingPackage()); - if (activity.getCallingPackage() != null - && activity.getCallingPackage().equals(Constants.PACKAGE_NAME)) { - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setHomeButtonEnabled(true); - } else { - actionBar.setDisplayHomeAsUpEnabled(false); - actionBar.setHomeButtonEnabled(false); - } - } - - /** - * Sets custom view on ActionBar for Done/Cancel activities - * - * @param actionBar - * @param firstText - * @param firstDrawableId - * @param firstOnClickListener - * @param secondText - * @param secondDrawableId - * @param secondOnClickListener - */ - public static void setTwoButtonView(ActionBar actionBar, - int firstText, int firstDrawableId, OnClickListener firstOnClickListener, - int secondText, int secondDrawableId, OnClickListener secondOnClickListener) { - - // Inflate the custom action bar view - final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext() - .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); - final View customActionBarView = inflater.inflate( - R.layout.actionbar_custom_view_done_cancel, null); - - TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); - firstTextView.setText(firstText); - firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); - customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( - firstOnClickListener); - TextView secondTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text)); - secondTextView.setText(secondText); - secondTextView.setCompoundDrawablesWithIntrinsicBounds(secondDrawableId, 0, 0, 0); - customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener( - secondOnClickListener); - - // Show the custom action bar view and hide the normal Home icon and title. - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setDisplayShowHomeEnabled(false); - actionBar.setDisplayShowCustomEnabled(true); - actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - } - - /** - * Sets custom view on ActionBar for Done activities - * - * @param actionBar - * @param firstText - * @param firstOnClickListener - */ - public static void setOneButtonView(ActionBar actionBar, int firstText, int firstDrawableId, - OnClickListener firstOnClickListener) { - // Inflate a "Done" custom action bar view to serve as the "Up" affordance. - final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext() - .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); - final View customActionBarView = inflater - .inflate(R.layout.actionbar_custom_view_done, null); - - TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); - firstTextView.setText(firstText); - firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); - customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( - firstOnClickListener); - - // Show the custom action bar view and hide the normal Home icon and title. - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setDisplayShowHomeEnabled(false); - actionBar.setDisplayShowCustomEnabled(true); - actionBar.setCustomView(customActionBarView); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java deleted file mode 100644 index f8ed21816..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.helper; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.content.Context; -import android.util.Patterns; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class ContactHelper { - - public static final List<String> getMailAccounts(Context context) { - final Account[] accounts = AccountManager.get(context).getAccounts(); - final Set<String> emailSet = new HashSet<String>(); - for (Account account : accounts) { - if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) { - emailSet.add(account.name); - } - } - return new ArrayList<String>(emailSet); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java deleted file mode 100644 index 810f22d8e..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.helper; - -import android.app.ProgressDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.support.v7.app.ActionBarActivity; -import android.widget.Toast; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; -import org.sufficientlysecure.keychain.util.Log; - -public class ExportHelper { - protected FileDialogFragment mFileDialog; - protected String mExportFilename; - - ActionBarActivity mActivity; - - public ExportHelper(ActionBarActivity activity) { - super(); - this.mActivity = activity; - } - - public void deleteKey(Uri dataUri, Handler deleteHandler) { - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(deleteHandler); - long masterKeyId = ProviderHelper.getMasterKeyId(mActivity, dataUri); - - DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, - new long[]{ masterKeyId }); - deleteKeyDialog.show(mActivity.getSupportFragmentManager(), "deleteKeyDialog"); - } - - /** - * Show dialog where to export keys - */ - public void showExportKeysDialog(final long[] masterKeyIds, final String exportFilename, - final boolean showSecretCheckbox) { - mExportFilename = exportFilename; - - // Message is received after file is selected - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == FileDialogFragment.MESSAGE_OKAY) { - Bundle data = message.getData(); - mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); - - exportKeys(masterKeyIds, data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED)); - } - } - }; - - // Create a new Messenger for the communication back - final Messenger messenger = new Messenger(returnHandler); - - DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { - public void run() { - String title = null; - if (masterKeyIds == null) { - // export all keys - title = mActivity.getString(R.string.title_export_keys); - } else { - // export only key specified at data uri - title = mActivity.getString(R.string.title_export_key); - } - - String message = mActivity.getString(R.string.specify_file_to_export_to); - String checkMsg = showSecretCheckbox ? - mActivity.getString(R.string.also_export_secret_keys) : null; - - mFileDialog = FileDialogFragment.newInstance(messenger, title, message, - exportFilename, checkMsg); - - mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog"); - } - }); - } - - /** - * Export keys - */ - public void exportKeys(long[] masterKeyIds, boolean exportSecret) { - Log.d(Constants.TAG, "exportKeys started"); - - // Send all information needed to service to export key in other thread - final Intent intent = new Intent(mActivity, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_EXPORT_KEYRING); - - // fill values for this action - Bundle data = new Bundle(); - - data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename); - data.putBoolean(KeychainIntentService.EXPORT_SECRET, exportSecret); - - if (masterKeyIds == null) { - data.putBoolean(KeychainIntentService.EXPORT_ALL, true); - } else { - data.putLongArray(KeychainIntentService.EXPORT_KEY_RING_MASTER_KEY_ID, masterKeyIds); - } - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after exporting is done in KeychainIntentService - KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(mActivity, - mActivity.getString(R.string.progress_exporting), - ProgressDialog.STYLE_HORIZONTAL, - true, - new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialogInterface) { - mActivity.stopService(intent); - } - }) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get returned data bundle - Bundle returnData = message.getData(); - - int exported = returnData.getInt(KeychainIntentService.RESULT_EXPORT); - String toastMessage; - if (exported == 1) { - toastMessage = mActivity.getString(R.string.key_exported); - } else if (exported > 0) { - toastMessage = mActivity.getString(R.string.keys_exported, exported); - } else { - toastMessage = mActivity.getString(R.string.no_keys_exported); - } - Toast.makeText(mActivity, toastMessage, Toast.LENGTH_SHORT).show(); - - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(exportHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - exportHandler.showProgressDialog(mActivity); - - // start service with intent - mActivity.startService(intent); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java deleted file mode 100644 index d24aeca52..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/FileHelper.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.helper; - -import android.app.Activity; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Environment; -import android.support.v4.app.Fragment; -import android.widget.Toast; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Log; - -public class FileHelper { - - /** - * Checks if external storage is mounted if file is located on external storage - * - * @param file - * @return true if storage is mounted - */ - public static boolean isStorageMounted(String file) { - if (file.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) { - if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - return false; - } - } - - return true; - } - - /** - * Opens the preferred installed file manager on Android and shows a toast if no manager is - * installed. - * - * @param activity - * @param filename default selected file, not supported by all file managers - * @param mimeType can be text/plain for example - * @param requestCode requestCode used to identify the result coming back from file manager to - * onActivityResult() in your activity - */ - public static void openFile(Activity activity, String filename, String mimeType, int requestCode) { - Intent intent = buildFileIntent(filename, mimeType); - - try { - activity.startActivityForResult(intent, requestCode); - } catch (ActivityNotFoundException e) { - // No compatible file manager was found. - Toast.makeText(activity, R.string.no_filemanager_installed, Toast.LENGTH_SHORT).show(); - } - } - - public static void openFile(Fragment fragment, String filename, String mimeType, int requestCode) { - Intent intent = buildFileIntent(filename, mimeType); - - try { - fragment.startActivityForResult(intent, requestCode); - } catch (ActivityNotFoundException e) { - // No compatible file manager was found. - Toast.makeText(fragment.getActivity(), R.string.no_filemanager_installed, - Toast.LENGTH_SHORT).show(); - } - } - - private static Intent buildFileIntent(String filename, String mimeType) { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - - intent.setData(Uri.parse("file://" + filename)); - intent.setType(mimeType); - - return intent; - } - - /** - * Get a file path from a Uri. - * <p/> - * from https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/ - * afilechooser/utils/FileUtils.java - * - * @param context - * @param uri - * @return - * @author paulburke - */ - public static String getPath(Context context, Uri uri) { - Log.d(Constants.TAG + " File -", - "Authority: " + uri.getAuthority() + ", Fragment: " + uri.getFragment() - + ", Port: " + uri.getPort() + ", Query: " + uri.getQuery() + ", Scheme: " - + uri.getScheme() + ", Host: " + uri.getHost() + ", Segments: " - + uri.getPathSegments().toString()); - - if ("content".equalsIgnoreCase(uri.getScheme())) { - String[] projection = {"_data"}; - Cursor cursor = null; - - try { - cursor = context.getContentResolver().query(uri, projection, null, null, null); - int columnIndex = cursor.getColumnIndexOrThrow("_data"); - if (cursor.moveToFirst()) { - return cursor.getString(columnIndex); - } - } catch (Exception e) { - // Eat it - } - } else if ("file".equalsIgnoreCase(uri.getScheme())) { - return uri.getPath(); - } - - return null; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java deleted file mode 100644 index b31a889f0..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.helper; - -import android.os.Bundle; -import android.text.SpannableStringBuilder; -import android.text.Spanned; - -import android.text.style.StrikethroughSpan; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.Iterator; -import java.util.Set; - -public class OtherHelper { - - /** - * Logs bundle content to debug for inspecting the content - * - * @param bundle - * @param bundleName - */ - public static void logDebugBundle(Bundle bundle, String bundleName) { - if (Constants.DEBUG) { - if (bundle != null) { - Set<String> ks = bundle.keySet(); - Iterator<String> iterator = ks.iterator(); - - Log.d(Constants.TAG, "Bundle " + bundleName + ":"); - Log.d(Constants.TAG, "------------------------------"); - while (iterator.hasNext()) { - String key = iterator.next(); - Object value = bundle.get(key); - - if (value != null) { - Log.d(Constants.TAG, key + " : " + value.toString()); - } else { - Log.d(Constants.TAG, key + " : null"); - } - } - Log.d(Constants.TAG, "------------------------------"); - } else { - Log.d(Constants.TAG, "Bundle " + bundleName + ": null"); - } - } - } - - public static SpannableStringBuilder strikeOutText(CharSequence text) { - SpannableStringBuilder sb = new SpannableStringBuilder(text); - sb.setSpan(new StrikethroughSpan(), 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); - return sb; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java deleted file mode 100644 index ca5555fea..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.helper; - -import android.content.Context; -import android.content.SharedPreferences; -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.openpgp.PGPEncryptedData; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; - -import java.util.Vector; - -/** - * Singleton Implementation of a Preference Helper - */ -public class Preferences { - private static Preferences sPreferences; - private SharedPreferences mSharedPreferences; - - public static synchronized Preferences getPreferences(Context context) { - return getPreferences(context, false); - } - - public static synchronized Preferences getPreferences(Context context, boolean forceNew) { - if (sPreferences == null || forceNew) { - sPreferences = new Preferences(context); - } - return sPreferences; - } - - private Preferences(Context context) { - mSharedPreferences = context.getSharedPreferences("APG.main", Context.MODE_PRIVATE); - } - - public String getLanguage() { - return mSharedPreferences.getString(Constants.Pref.LANGUAGE, ""); - } - - public void setLanguage(String value) { - SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putString(Constants.Pref.LANGUAGE, value); - editor.commit(); - } - - public long getPassphraseCacheTtl() { - int ttl = mSharedPreferences.getInt(Constants.Pref.PASSPHRASE_CACHE_TTL, 180); - // fix the value if it was set to "never" in previous versions, which currently is not - // supported - if (ttl == 0) { - ttl = 180; - } - return (long) ttl; - } - - public void setPassphraseCacheTtl(int value) { - SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putInt(Constants.Pref.PASSPHRASE_CACHE_TTL, value); - editor.commit(); - } - - public int getDefaultEncryptionAlgorithm() { - return mSharedPreferences.getInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM, - PGPEncryptedData.AES_256); - } - - public void setDefaultEncryptionAlgorithm(int value) { - SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM, value); - editor.commit(); - } - - public int getDefaultHashAlgorithm() { - return mSharedPreferences.getInt(Constants.Pref.DEFAULT_HASH_ALGORITHM, - HashAlgorithmTags.SHA512); - } - - public void setDefaultHashAlgorithm(int value) { - SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putInt(Constants.Pref.DEFAULT_HASH_ALGORITHM, value); - editor.commit(); - } - - public int getDefaultMessageCompression() { - return mSharedPreferences.getInt(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION, - Id.choice.compression.zlib); - } - - public void setDefaultMessageCompression(int value) { - SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putInt(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION, value); - editor.commit(); - } - - public int getDefaultFileCompression() { - return mSharedPreferences.getInt(Constants.Pref.DEFAULT_FILE_COMPRESSION, - Id.choice.compression.none); - } - - public void setDefaultFileCompression(int value) { - SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putInt(Constants.Pref.DEFAULT_FILE_COMPRESSION, value); - editor.commit(); - } - - public boolean getDefaultAsciiArmor() { - return mSharedPreferences.getBoolean(Constants.Pref.DEFAULT_ASCII_ARMOR, false); - } - - public void setDefaultAsciiArmor(boolean value) { - SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putBoolean(Constants.Pref.DEFAULT_ASCII_ARMOR, value); - editor.commit(); - } - - public boolean getForceV3Signatures() { - return mSharedPreferences.getBoolean(Constants.Pref.FORCE_V3_SIGNATURES, false); - } - - public void setForceV3Signatures(boolean value) { - SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putBoolean(Constants.Pref.FORCE_V3_SIGNATURES, value); - editor.commit(); - } - - public String[] getKeyServers() { - String rawData = mSharedPreferences.getString(Constants.Pref.KEY_SERVERS, - Constants.Defaults.KEY_SERVERS); - Vector<String> servers = new Vector<String>(); - String chunks[] = rawData.split(","); - for (String c : chunks) { - String tmp = c.trim(); - if (tmp.length() > 0) { - servers.add(tmp); - } - } - return servers.toArray(chunks); - } - - public void setKeyServers(String[] value) { - SharedPreferences.Editor editor = mSharedPreferences.edit(); - String rawData = ""; - for (String v : value) { - String tmp = v.trim(); - if (tmp.length() == 0) { - continue; - } - if (!"".equals(rawData)) { - rawData += ","; - } - rawData += tmp; - } - editor.putString(Constants.Pref.KEY_SERVERS, rawData); - editor.commit(); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java deleted file mode 100644 index c6c62d649..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.pgp; - -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.PGPSignatureList; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; - - -public class PgpConversionHelper { - - /** - * Convert from byte[] to PGPKeyRing - * - * @param keysBytes - * @return - */ - public static PGPKeyRing BytesToPGPKeyRing(byte[] keysBytes) { - PGPObjectFactory factory = new PGPObjectFactory(keysBytes); - PGPKeyRing keyRing = null; - try { - if ((keyRing = (PGPKeyRing) factory.nextObject()) == null) { - Log.e(Constants.TAG, "No keys given!"); - } - } catch (IOException e) { - Log.e(Constants.TAG, "Error while converting to PGPKeyRing!", e); - } - - return keyRing; - } - - /** - * Convert from byte[] to ArrayList<PGPSecretKey> - * - * @param keysBytes - * @return - */ - public static ArrayList<PGPSecretKey> BytesToPGPSecretKeyList(byte[] keysBytes) { - PGPObjectFactory factory = new PGPObjectFactory(keysBytes); - Object obj = null; - ArrayList<PGPSecretKey> keys = new ArrayList<PGPSecretKey>(); - try { - while ((obj = factory.nextObject()) != null) { - PGPSecretKey secKey = null; - if (obj instanceof PGPSecretKey) { - secKey = (PGPSecretKey) obj; - if (secKey == null) { - Log.e(Constants.TAG, "No keys given!"); - } - keys.add(secKey); - } else if (obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings - PGPSecretKeyRing keyRing = null; - keyRing = (PGPSecretKeyRing) obj; - if (keyRing == null) { - Log.e(Constants.TAG, "No keys given!"); - } - @SuppressWarnings("unchecked") - Iterator<PGPSecretKey> itr = keyRing.getSecretKeys(); - while (itr.hasNext()) { - keys.add(itr.next()); - } - } - } - } catch (IOException e) { - } - - return keys; - } - - /** - * Convert from byte[] to PGPSecretKey - * <p/> - * Singles keys are encoded as keyRings with one single key in it by Bouncy Castle - * - * @param keyBytes - * @return - */ - public static PGPSecretKey BytesToPGPSecretKey(byte[] keyBytes) { - PGPObjectFactory factory = new PGPObjectFactory(keyBytes); - Object obj = null; - try { - obj = factory.nextObject(); - } catch (IOException e) { - Log.e(Constants.TAG, "Error while converting to PGPSecretKey!", e); - } - PGPSecretKey secKey = null; - if (obj instanceof PGPSecretKey) { - if ((secKey = (PGPSecretKey) obj) == null) { - Log.e(Constants.TAG, "No keys given!"); - } - } else if (obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings - PGPSecretKeyRing keyRing = null; - if ((keyRing = (PGPSecretKeyRing) obj) == null) { - Log.e(Constants.TAG, "No keys given!"); - } - secKey = keyRing.getSecretKey(); - } - - return secKey; - } - - /** - * Convert from byte[] to PGPSignature - * - * @param sigBytes - * @return - */ - public static PGPSignature BytesToPGPSignature(byte[] sigBytes) { - PGPObjectFactory factory = new PGPObjectFactory(sigBytes); - PGPSignatureList signatures = null; - try { - if ((signatures = (PGPSignatureList) factory.nextObject()) == null || signatures.isEmpty()) { - Log.e(Constants.TAG, "No signatures given!"); - return null; - } - } catch (IOException e) { - Log.e(Constants.TAG, "Error while converting to PGPSignature!", e); - return null; - } - - return signatures.get(0); - } - - /** - * Convert from ArrayList<PGPSecretKey> to byte[] - * - * @param keys - * @return - */ - public static byte[] PGPSecretKeyArrayListToBytes(ArrayList<PGPSecretKey> keys) { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - for (PGPSecretKey key : keys) { - try { - key.encode(os); - } catch (IOException e) { - Log.e(Constants.TAG, "Error while converting ArrayList<PGPSecretKey> to byte[]!", e); - } - } - - return os.toByteArray(); - } - - /** - * Convert from PGPSecretKey to byte[] - * - * @param key - * @return - */ - public static byte[] PGPSecretKeyToBytes(PGPSecretKey key) { - try { - return key.getEncoded(); - } catch (IOException e) { - Log.e(Constants.TAG, "Encoding failed", e); - - return null; - } - } - - /** - * Convert from PGPSecretKeyRing to byte[] - * - * @param keyRing - * @return - */ - public static byte[] PGPSecretKeyRingToBytes(PGPSecretKeyRing keyRing) { - try { - return keyRing.getEncoded(); - } catch (IOException e) { - Log.e(Constants.TAG, "Encoding failed", e); - - return null; - } - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java deleted file mode 100644 index 8a0bf99d7..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ /dev/null @@ -1,836 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.pgp; - -import android.content.Context; - -import org.openintents.openpgp.OpenPgpSignatureResult; -import org.spongycastle.bcpg.ArmoredInputStream; -import org.spongycastle.bcpg.SignatureSubpacketTags; -import org.spongycastle.openpgp.PGPCompressedData; -import org.spongycastle.openpgp.PGPEncryptedData; -import org.spongycastle.openpgp.PGPEncryptedDataList; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPLiteralData; -import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPOnePassSignature; -import org.spongycastle.openpgp.PGPOnePassSignatureList; -import org.spongycastle.openpgp.PGPPBEEncryptedData; -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.PGPSignatureList; -import org.spongycastle.openpgp.PGPSignatureSubpacketVector; -import org.spongycastle.openpgp.PGPUtil; -import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; -import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.SignatureException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Set; - -/** - * This class uses a Builder pattern! - */ -public class PgpDecryptVerify { - private Context mContext; - private InputData mData; - private OutputStream mOutStream; - - private ProgressDialogUpdater mProgressDialogUpdater; - private boolean mAllowSymmetricDecryption; - private String mPassphrase; - private Set<Long> mAllowedKeyIds; - - private PgpDecryptVerify(Builder builder) { - // private Constructor can only be called from Builder - this.mContext = builder.mContext; - this.mData = builder.mData; - this.mOutStream = builder.mOutStream; - - this.mProgressDialogUpdater = builder.mProgressDialogUpdater; - this.mAllowSymmetricDecryption = builder.mAllowSymmetricDecryption; - this.mPassphrase = builder.mPassphrase; - this.mAllowedKeyIds = builder.mAllowedKeyIds; - } - - public static class Builder { - // mandatory parameter - private Context mContext; - private InputData mData; - private OutputStream mOutStream; - - // optional - private ProgressDialogUpdater mProgressDialogUpdater = null; - private boolean mAllowSymmetricDecryption = true; - private String mPassphrase = null; - private Set<Long> mAllowedKeyIds = null; - - public Builder(Context context, InputData data, OutputStream outStream) { - this.mContext = context; - this.mData = data; - this.mOutStream = outStream; - } - - public Builder progressDialogUpdater(ProgressDialogUpdater progressDialogUpdater) { - this.mProgressDialogUpdater = progressDialogUpdater; - return this; - } - - public Builder allowSymmetricDecryption(boolean allowSymmetricDecryption) { - this.mAllowSymmetricDecryption = allowSymmetricDecryption; - return this; - } - - public Builder passphrase(String passphrase) { - this.mPassphrase = passphrase; - return this; - } - - /** - * Allow these key ids alone for decryption. - * This means only ciphertexts encrypted for one of these private key can be decrypted. - * - * @param allowedKeyIds - * @return - */ - public Builder allowedKeyIds(Set<Long> allowedKeyIds) { - this.mAllowedKeyIds = allowedKeyIds; - return this; - } - - public PgpDecryptVerify build() { - return new PgpDecryptVerify(this); - } - } - - public void updateProgress(int message, int current, int total) { - if (mProgressDialogUpdater != null) { - mProgressDialogUpdater.setProgress(message, current, total); - } - } - - public void updateProgress(int current, int total) { - if (mProgressDialogUpdater != null) { - mProgressDialogUpdater.setProgress(current, total); - } - } - - /** - * Decrypts and/or verifies data based on parameters of class - * - * @return - * @throws IOException - * @throws PgpGeneralException - * @throws PGPException - * @throws SignatureException - */ - public PgpDecryptVerifyResult execute() - throws IOException, PgpGeneralException, PGPException, SignatureException { - // automatically works with ascii armor input and binary - InputStream in = PGPUtil.getDecoderStream(mData.getInputStream()); - if (in instanceof ArmoredInputStream) { - ArmoredInputStream aIn = (ArmoredInputStream) in; - // it is ascii armored - Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine()); - - if (aIn.isClearText()) { - // a cleartext signature, verify it with the other method - return verifyCleartextSignature(aIn); - } - // else: ascii armored encryption! go on... - } - - return decryptVerify(in); - } - - /** - * Decrypt and/or verifies binary or ascii armored pgp - * - * @param in - * @return - * @throws IOException - * @throws PgpGeneralException - * @throws PGPException - * @throws SignatureException - */ - private PgpDecryptVerifyResult decryptVerify(InputStream in) - throws IOException, PgpGeneralException, PGPException, SignatureException { - PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult(); - - PGPObjectFactory pgpF = new PGPObjectFactory(in); - PGPEncryptedDataList enc; - Object o = pgpF.nextObject(); - - int currentProgress = 0; - updateProgress(R.string.progress_reading_data, currentProgress, 100); - - if (o instanceof PGPEncryptedDataList) { - enc = (PGPEncryptedDataList) o; - } else { - enc = (PGPEncryptedDataList) pgpF.nextObject(); - } - - if (enc == null) { - throw new PgpGeneralException(mContext.getString(R.string.error_invalid_data)); - } - - InputStream clear; - PGPEncryptedData encryptedData; - - currentProgress += 5; - - PGPPublicKeyEncryptedData encryptedDataAsymmetric = null; - PGPPBEEncryptedData encryptedDataSymmetric = null; - PGPSecretKey secretKey = null; - Iterator<?> it = enc.getEncryptedDataObjects(); - boolean symmetricPacketFound = false; - // find secret key - while (it.hasNext()) { - Object obj = it.next(); - if (obj instanceof PGPPublicKeyEncryptedData) { - updateProgress(R.string.progress_finding_key, currentProgress, 100); - - PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj; - long masterKeyId = ProviderHelper.getMasterKeyId(mContext, - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(encData.getKeyID())) - ); - PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRing(mContext, masterKeyId); - if (secretKeyRing == null) { - throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found)); - } - secretKey = secretKeyRing.getSecretKey(encData.getKeyID()); - if (secretKey == null) { - throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found)); - } - // secret key exists in database - - // allow only a specific key for decryption? - if (mAllowedKeyIds != null) { - Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID()); - Log.d(Constants.TAG, "allowedKeyIds: " + mAllowedKeyIds); - Log.d(Constants.TAG, "masterKeyId: " + masterKeyId); - - if (!mAllowedKeyIds.contains(masterKeyId)) { - throw new PgpGeneralException( - mContext.getString(R.string.error_no_secret_key_found)); - } - } - - encryptedDataAsymmetric = encData; - - // if no passphrase was explicitly set try to get it from the cache service - if (mPassphrase == null) { - // returns "" if key has no passphrase - mPassphrase = - PassphraseCacheService.getCachedPassphrase(mContext, masterKeyId); - - // if passphrase was not cached, return here - // indicating that a passphrase is missing! - if (mPassphrase == null) { - returnData.setKeyIdPassphraseNeeded(masterKeyId); - returnData.setStatus(PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED); - return returnData; - } - } - - // break out of while, only get first object here - // TODO???: There could be more pgp objects, which are not decrypted! - break; - } else if (mAllowSymmetricDecryption && obj instanceof PGPPBEEncryptedData) { - symmetricPacketFound = true; - - encryptedDataSymmetric = (PGPPBEEncryptedData) obj; - - // if no passphrase is given, return here - // indicating that a passphrase is missing! - if (mPassphrase == null) { - returnData.setStatus(PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED); - return returnData; - } - - // break out of while, only get first object here - // TODO???: There could be more pgp objects, which are not decrypted! - break; - } - } - - if (symmetricPacketFound) { - updateProgress(R.string.progress_preparing_streams, currentProgress, 100); - - PGPDigestCalculatorProvider digestCalcProvider = new JcaPGPDigestCalculatorProviderBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(); - PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder( - digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - mPassphrase.toCharArray()); - - clear = encryptedDataSymmetric.getDataStream(decryptorFactory); - - encryptedData = encryptedDataSymmetric; - currentProgress += 5; - } else { - if (secretKey == null) { - throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found)); - } - - currentProgress += 5; - updateProgress(R.string.progress_extracting_key, currentProgress, 100); - PGPPrivateKey privateKey; - try { - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - mPassphrase.toCharArray()); - privateKey = secretKey.extractPrivateKey(keyDecryptor); - } catch (PGPException e) { - throw new PGPException(mContext.getString(R.string.error_wrong_passphrase)); - } - if (privateKey == null) { - throw new PgpGeneralException( - mContext.getString(R.string.error_could_not_extract_private_key)); - } - currentProgress += 5; - updateProgress(R.string.progress_preparing_streams, currentProgress, 100); - - PublicKeyDataDecryptorFactory decryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(privateKey); - - clear = encryptedDataAsymmetric.getDataStream(decryptorFactory); - - encryptedData = encryptedDataAsymmetric; - currentProgress += 5; - } - - PGPObjectFactory plainFact = new PGPObjectFactory(clear); - Object dataChunk = plainFact.nextObject(); - PGPOnePassSignature signature = null; - OpenPgpSignatureResult signatureResult = null; - PGPPublicKey signatureKey = null; - int signatureIndex = -1; - - if (dataChunk instanceof PGPCompressedData) { - updateProgress(R.string.progress_decompressing_data, currentProgress, 100); - - PGPObjectFactory fact = new PGPObjectFactory( - ((PGPCompressedData) dataChunk).getDataStream()); - dataChunk = fact.nextObject(); - plainFact = fact; - currentProgress += 10; - } - - long signatureKeyId = 0; - if (dataChunk instanceof PGPOnePassSignatureList) { - updateProgress(R.string.progress_processing_signature, currentProgress, 100); - - signatureResult = new OpenPgpSignatureResult(); - PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk; - for (int i = 0; i < sigList.size(); ++i) { - signature = sigList.get(i); - signatureKey = ProviderHelper - .getPGPPublicKeyRing(mContext, signature.getKeyID()).getPublicKey(); - if (signatureKeyId == 0) { - signatureKeyId = signature.getKeyID(); - } - if (signatureKey == null) { - signature = null; - } else { - signatureIndex = i; - signatureKeyId = signature.getKeyID(); - String userId = null; - PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId( - mContext, signatureKeyId); - if (signKeyRing != null) { - userId = PgpKeyHelper.getMainUserId(signKeyRing.getPublicKey()); - } - signatureResult.setUserId(userId); - break; - } - } - - signatureResult.setKeyId(signatureKeyId); - - if (signature != null) { - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - signature.init(contentVerifierBuilderProvider, signatureKey); - } else { - signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY); - } - - dataChunk = plainFact.nextObject(); - currentProgress += 10; - } - - if (dataChunk instanceof PGPSignatureList) { - dataChunk = plainFact.nextObject(); - } - - if (dataChunk instanceof PGPLiteralData) { - updateProgress(R.string.progress_decrypting, currentProgress, 100); - - PGPLiteralData literalData = (PGPLiteralData) dataChunk; - - byte[] buffer = new byte[1 << 16]; - InputStream dataIn = literalData.getInputStream(); - - int startProgress = currentProgress; - int endProgress = 100; - if (signature != null) { - endProgress = 90; - } else if (encryptedData.isIntegrityProtected()) { - endProgress = 95; - } - - int n; - // TODO: progress calculation is broken here! Try to rework it based on commented code! -// int progress = 0; - long startPos = mData.getStreamPosition(); - while ((n = dataIn.read(buffer)) > 0) { - mOutStream.write(buffer, 0, n); -// progress += n; - if (signature != null) { - try { - signature.update(buffer, 0, n); - } catch (SignatureException e) { - signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR); - signature = null; - } - } - // TODO: dead code?! - // unknown size, but try to at least have a moving, slowing down progress bar -// currentProgress = startProgress + (endProgress - startProgress) * progress -// / (progress + 100000); - if (mData.getSize() - startPos == 0) { - currentProgress = endProgress; - } else { - currentProgress = (int) (startProgress + (endProgress - startProgress) - * (mData.getStreamPosition() - startPos) / (mData.getSize() - startPos)); - } - updateProgress(currentProgress, 100); - } - - if (signature != null) { - updateProgress(R.string.progress_verifying_signature, 90, 100); - - PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject(); - PGPSignature messageSignature = signatureList.get(signatureIndex); - - // these are not cleartext signatures! - // TODO: what about binary signatures? - signatureResult.setSignatureOnly(false); - - //Now check binding signatures - boolean validKeyBinding = verifyKeyBinding(mContext, messageSignature, signatureKey); - boolean validSignature = signature.verify(messageSignature); - - // TODO: implement CERTIFIED! - if (validKeyBinding & validSignature) { - signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED); - } - } - } - - if (encryptedData.isIntegrityProtected()) { - updateProgress(R.string.progress_verifying_integrity, 95, 100); - - if (encryptedData.verify()) { - // passed - Log.d(Constants.TAG, "Integrity verification: success!"); - } else { - // failed - Log.d(Constants.TAG, "Integrity verification: failed!"); - throw new PgpGeneralException(mContext.getString(R.string.error_integrity_check_failed)); - } - } else { - // no integrity check - Log.e(Constants.TAG, "Encrypted data was not integrity protected!"); - // TODO: inform user? - } - - updateProgress(R.string.progress_done, 100, 100); - - returnData.setSignatureResult(signatureResult); - return returnData; - } - - /** - * This method verifies cleartext signatures - * as defined in http://tools.ietf.org/html/rfc4880#section-7 - * <p/> - * The method is heavily based on - * pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java - * - * @return - * @throws IOException - * @throws PgpGeneralException - * @throws PGPException - * @throws SignatureException - */ - private PgpDecryptVerifyResult verifyCleartextSignature(ArmoredInputStream aIn) - throws IOException, PgpGeneralException, PGPException, SignatureException { - PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult(); - OpenPgpSignatureResult signatureResult = new OpenPgpSignatureResult(); - // cleartext signatures are never encrypted ;) - signatureResult.setSignatureOnly(true); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - updateProgress(R.string.progress_done, 0, 100); - - ByteArrayOutputStream lineOut = new ByteArrayOutputStream(); - int lookAhead = readInputLine(lineOut, aIn); - byte[] lineSep = getLineSeparator(); - - byte[] line = lineOut.toByteArray(); - out.write(line, 0, getLengthWithoutSeparator(line)); - out.write(lineSep); - - while (lookAhead != -1 && aIn.isClearText()) { - lookAhead = readInputLine(lineOut, lookAhead, aIn); - line = lineOut.toByteArray(); - out.write(line, 0, getLengthWithoutSeparator(line)); - out.write(lineSep); - } - - out.close(); - - byte[] clearText = out.toByteArray(); - mOutStream.write(clearText); - - updateProgress(R.string.progress_processing_signature, 60, 100); - PGPObjectFactory pgpFact = new PGPObjectFactory(aIn); - - PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject(); - if (sigList == null) { - throw new PgpGeneralException(mContext.getString(R.string.error_corrupt_data)); - } - PGPSignature signature = null; - long signatureKeyId = 0; - PGPPublicKey signatureKey = null; - for (int i = 0; i < sigList.size(); ++i) { - - signature = sigList.get(i); - signatureKeyId = signature.getKeyID(); - - // find data about this subkey - HashMap<String, Object> data = ProviderHelper.getGenericData(mContext, - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(signature.getKeyID())), - new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID }, - new int[] { ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_STRING }); - // any luck? otherwise, try next. - if(data.get(KeyRings.MASTER_KEY_ID) == null) { - signature = null; - // do NOT reset signatureKeyId, that one is shown when no known one is found! - continue; - } - - // this one can't fail now (yay database constraints) - signatureKey = ProviderHelper.getPGPPublicKeyRing(mContext, (Long) data.get(KeyRings.MASTER_KEY_ID)).getPublicKey(); - signatureResult.setUserId((String) data.get(KeyRings.USER_ID)); - - break; - } - - signatureResult.setKeyId(signatureKeyId); - - if (signature == null) { - signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY); - returnData.setSignatureResult(signatureResult); - - updateProgress(R.string.progress_done, 100, 100); - return returnData; - } - - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - signature.init(contentVerifierBuilderProvider, signatureKey); - - InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText)); - - lookAhead = readInputLine(lineOut, sigIn); - - processLine(signature, lineOut.toByteArray()); - - if (lookAhead != -1) { - do { - lookAhead = readInputLine(lineOut, lookAhead, sigIn); - - signature.update((byte) '\r'); - signature.update((byte) '\n'); - - processLine(signature, lineOut.toByteArray()); - } while (lookAhead != -1); - } - - //Now check binding signatures - boolean validKeyBinding = verifyKeyBinding(mContext, signature, signatureKey); - boolean validSignature = signature.verify(); - - if (validSignature & validKeyBinding) { - signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED); - } - - // TODO: what about SIGNATURE_SUCCESS_CERTIFIED and SIGNATURE_ERROR???? - - returnData.setSignatureResult(signatureResult); - - updateProgress(R.string.progress_done, 100, 100); - return returnData; - } - - private static boolean verifyKeyBinding(Context context, - PGPSignature signature, PGPPublicKey signatureKey) { - long signatureKeyId = signature.getKeyID(); - boolean validKeyBinding = false; - - PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId(context, - signatureKeyId); - PGPPublicKey mKey = null; - if (signKeyRing != null) { - mKey = signKeyRing.getPublicKey(); - } - - if (signature.getKeyID() != mKey.getKeyID()) { - validKeyBinding = verifyKeyBinding(mKey, signatureKey); - } else { //if the key used to make the signature was the master key, no need to check binding sigs - validKeyBinding = true; - } - return validKeyBinding; - } - - private static boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { - boolean validSubkeyBinding = false; - boolean validTempSubkeyBinding = false; - boolean validPrimaryKeyBinding = false; - - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - Iterator<PGPSignature> itr = signingPublicKey.getSignatures(); - - while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong? - //gpg has an invalid subkey binding error on key import I think, but doesn't shout - //about keys without subkey signing. Can't get it to import a slightly broken one - //either, so we will err on bad subkey binding here. - PGPSignature sig = itr.next(); - if (sig.getKeyID() == masterPublicKey.getKeyID() && - sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) { - //check and if ok, check primary key binding. - try { - sig.init(contentVerifierBuilderProvider, masterPublicKey); - validTempSubkeyBinding = sig.verifyCertification(masterPublicKey, signingPublicKey); - } catch (PGPException e) { - continue; - } catch (SignatureException e) { - continue; - } - - if (validTempSubkeyBinding) { - validSubkeyBinding = true; - } - if (validTempSubkeyBinding) { - validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(), - masterPublicKey, signingPublicKey); - if (validPrimaryKeyBinding) { - break; - } - validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(), - masterPublicKey, signingPublicKey); - if (validPrimaryKeyBinding) { - break; - } - } - } - } - return (validSubkeyBinding & validPrimaryKeyBinding); - } - - private static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts, - PGPPublicKey masterPublicKey, - PGPPublicKey signingPublicKey) { - boolean validPrimaryKeyBinding = false; - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - PGPSignatureList eSigList; - - if (pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) { - try { - eSigList = pkts.getEmbeddedSignatures(); - } catch (IOException e) { - return false; - } catch (PGPException e) { - return false; - } - for (int j = 0; j < eSigList.size(); ++j) { - PGPSignature emSig = eSigList.get(j); - if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) { - try { - emSig.init(contentVerifierBuilderProvider, signingPublicKey); - validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey); - if (validPrimaryKeyBinding) { - break; - } - } catch (PGPException e) { - continue; - } catch (SignatureException e) { - continue; - } - } - } - } - - return validPrimaryKeyBinding; - } - - /** - * Mostly taken from ClearSignedFileProcessor in Bouncy Castle - * - * @param sig - * @param line - * @throws SignatureException - */ - private static void processLine(PGPSignature sig, byte[] line) - throws SignatureException { - int length = getLengthWithoutWhiteSpace(line); - if (length > 0) { - sig.update(line, 0, length); - } - } - - private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn) - throws IOException { - bOut.reset(); - - int lookAhead = -1; - int ch; - - while ((ch = fIn.read()) >= 0) { - bOut.write(ch); - if (ch == '\r' || ch == '\n') { - lookAhead = readPassedEOL(bOut, ch, fIn); - break; - } - } - - return lookAhead; - } - - private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn) - throws IOException { - bOut.reset(); - - int ch = lookAhead; - - do { - bOut.write(ch); - if (ch == '\r' || ch == '\n') { - lookAhead = readPassedEOL(bOut, ch, fIn); - break; - } - } while ((ch = fIn.read()) >= 0); - - if (ch < 0) { - lookAhead = -1; - } - - return lookAhead; - } - - private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn) - throws IOException { - int lookAhead = fIn.read(); - - if (lastCh == '\r' && lookAhead == '\n') { - bOut.write(lookAhead); - lookAhead = fIn.read(); - } - - return lookAhead; - } - - private static int getLengthWithoutSeparator(byte[] line) { - int end = line.length - 1; - - while (end >= 0 && isLineEnding(line[end])) { - end--; - } - - return end + 1; - } - - private static boolean isLineEnding(byte b) { - return b == '\r' || b == '\n'; - } - - private static int getLengthWithoutWhiteSpace(byte[] line) { - int end = line.length - 1; - - while (end >= 0 && isWhiteSpace(line[end])) { - end--; - } - - return end + 1; - } - - private static boolean isWhiteSpace(byte b) { - return b == '\r' || b == '\n' || b == '\t' || b == ' '; - } - - private static byte[] getLineSeparator() { - String nl = System.getProperty("line.separator"); - byte[] nlBytes = new byte[nl.length()]; - - for (int i = 0; i != nlBytes.length; i++) { - nlBytes[i] = (byte) nl.charAt(i); - } - - return nlBytes; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java deleted file mode 100644 index ad240e834..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.pgp; - -import android.os.Parcel; -import android.os.Parcelable; - -import org.openintents.openpgp.OpenPgpSignatureResult; - -public class PgpDecryptVerifyResult implements Parcelable { - public static final int SUCCESS = 1; - public static final int KEY_PASSHRASE_NEEDED = 2; - public static final int SYMMETRIC_PASSHRASE_NEEDED = 3; - - int mStatus; - long mKeyIdPassphraseNeeded; - - OpenPgpSignatureResult mSignatureResult; - - public int getStatus() { - return mStatus; - } - - public void setStatus(int mStatus) { - this.mStatus = mStatus; - } - - public long getKeyIdPassphraseNeeded() { - return mKeyIdPassphraseNeeded; - } - - public void setKeyIdPassphraseNeeded(long mKeyIdPassphraseNeeded) { - this.mKeyIdPassphraseNeeded = mKeyIdPassphraseNeeded; - } - - public OpenPgpSignatureResult getSignatureResult() { - return mSignatureResult; - } - - public void setSignatureResult(OpenPgpSignatureResult signatureResult) { - this.mSignatureResult = signatureResult; - } - - public PgpDecryptVerifyResult() { - - } - - public PgpDecryptVerifyResult(PgpDecryptVerifyResult b) { - this.mStatus = b.mStatus; - this.mKeyIdPassphraseNeeded = b.mKeyIdPassphraseNeeded; - this.mSignatureResult = b.mSignatureResult; - } - - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mStatus); - dest.writeLong(mKeyIdPassphraseNeeded); - dest.writeParcelable(mSignatureResult, 0); - } - - public static final Creator<PgpDecryptVerifyResult> CREATOR = new Creator<PgpDecryptVerifyResult>() { - public PgpDecryptVerifyResult createFromParcel(final Parcel source) { - PgpDecryptVerifyResult vr = new PgpDecryptVerifyResult(); - vr.mStatus = source.readInt(); - vr.mKeyIdPassphraseNeeded = source.readLong(); - vr.mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader()); - return vr; - } - - public PgpDecryptVerifyResult[] newArray(final int size) { - return new PgpDecryptVerifyResult[size]; - } - }; -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java deleted file mode 100644 index f884b1776..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.pgp; - -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; - -import org.spongycastle.openpgp.PGPEncryptedDataList; -import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPUtil; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.security.SecureRandom; -import java.util.Iterator; -import java.util.regex.Pattern; - -public class PgpHelper { - - public static final Pattern PGP_MESSAGE = Pattern.compile( - ".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL); - - public static final Pattern PGP_CLEARTEXT_SIGNATURE = Pattern - .compile(".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----" + - "BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*", - Pattern.DOTALL); - - public static final Pattern PGP_PUBLIC_KEY = Pattern.compile( - ".*?(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----).*", - Pattern.DOTALL); - - public static String getVersion(Context context) { - String version = null; - try { - PackageInfo pi = context.getPackageManager().getPackageInfo(Constants.PACKAGE_NAME, 0); - version = pi.versionName; - return version; - } catch (NameNotFoundException e) { - Log.e(Constants.TAG, "Version could not be retrieved!", e); - return "0.0.0"; - } - } - - public static String getFullVersion(Context context) { - return "OpenPGP Keychain v" + getVersion(context); - } - - public static long getDecryptionKeyId(Context context, InputStream inputStream) - throws PgpGeneralException, NoAsymmetricEncryptionException, IOException { - InputStream in = PGPUtil.getDecoderStream(inputStream); - PGPObjectFactory pgpF = new PGPObjectFactory(in); - PGPEncryptedDataList enc; - Object o = pgpF.nextObject(); - - // the first object might be a PGP marker packet. - if (o instanceof PGPEncryptedDataList) { - enc = (PGPEncryptedDataList) o; - } else { - enc = (PGPEncryptedDataList) pgpF.nextObject(); - } - - if (enc == null) { - throw new PgpGeneralException(context.getString(R.string.error_invalid_data)); - } - - // TODO: currently we always only look at the first known key - // find the secret key - PGPSecretKey secretKey = null; - Iterator<?> it = enc.getEncryptedDataObjects(); - boolean gotAsymmetricEncryption = false; - while (it.hasNext()) { - Object obj = it.next(); - if (obj instanceof PGPPublicKeyEncryptedData) { - gotAsymmetricEncryption = true; - PGPPublicKeyEncryptedData pbe = (PGPPublicKeyEncryptedData) obj; - secretKey = ProviderHelper.getPGPSecretKeyRing(context, pbe.getKeyID()).getSecretKey(); - if (secretKey != null) { - break; - } - } - } - - if (!gotAsymmetricEncryption) { - throw new NoAsymmetricEncryptionException(); - } - - if (secretKey == null) { - return Id.key.none; - } - - return secretKey.getKeyID(); - } - - public static int getStreamContent(Context context, InputStream inStream) throws IOException { - InputStream in = PGPUtil.getDecoderStream(inStream); - PGPObjectFactory pgpF = new PGPObjectFactory(in); - Object object = pgpF.nextObject(); - while (object != null) { - if (object instanceof PGPPublicKeyRing || object instanceof PGPSecretKeyRing) { - return Id.content.keys; - } else if (object instanceof PGPEncryptedDataList) { - return Id.content.encrypted_data; - } - object = pgpF.nextObject(); - } - - return Id.content.unknown; - } - - /** - * Generate a random filename - * - * @param length - * @return - */ - public static String generateRandomFilename(int length) { - SecureRandom random = new SecureRandom(); - - byte bytes[] = new byte[length]; - random.nextBytes(bytes); - String result = ""; - for (int i = 0; i < length; ++i) { - int v = (bytes[i] + 256) % 64; - if (v < 10) { - result += (char) ('0' + v); - } else if (v < 36) { - result += (char) ('A' + v - 10); - } else if (v < 62) { - result += (char) ('a' + v - 36); - } else if (v == 62) { - result += '_'; - } else if (v == 63) { - result += '.'; - } - } - return result; - } - - /** - * Go once through stream to get length of stream. The length is later used to display progress - * when encrypting/decrypting - * - * @param in - * @return - * @throws IOException - */ - public static long getLengthOfStream(InputStream in) throws IOException { - long size = 0; - long n = 0; - byte dummy[] = new byte[0x10000]; - while ((n = in.read(dummy)) > 0) { - size += n; - } - return size; - } - - /** - * Deletes file securely by overwriting it with random data before deleting it. - * <p/> - * TODO: Does this really help on flash storage? - * - * @param context - * @param progress - * @param file - * @throws IOException - */ - public static void deleteFileSecurely(Context context, ProgressDialogUpdater progress, File file) - throws IOException { - long length = file.length(); - SecureRandom random = new SecureRandom(); - RandomAccessFile raf = new RandomAccessFile(file, "rws"); - raf.seek(0); - raf.getFilePointer(); - byte[] data = new byte[1 << 16]; - int pos = 0; - String msg = context.getString(R.string.progress_deleting_securely, file.getName()); - while (pos < length) { - if (progress != null) { - progress.setProgress(msg, (int) (100 * pos / length), 100); - } - random.nextBytes(data); - raf.write(data); - pos += data.length; - } - raf.close(); - file.delete(); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java deleted file mode 100644 index d03f3ccc2..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.pgp; - -import android.content.Context; -import android.os.Bundle; -import android.os.Environment; - -import org.spongycastle.bcpg.ArmoredOutputStream; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; -import org.sufficientlysecure.keychain.util.HkpKeyServer; -import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException; -import org.sufficientlysecure.keychain.util.KeychainServiceListener; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -public class PgpImportExport { - - private Context mContext; - private ProgressDialogUpdater mProgress; - - private KeychainServiceListener mKeychainServiceListener; - - public PgpImportExport(Context context, ProgressDialogUpdater progress) { - super(); - this.mContext = context; - this.mProgress = progress; - } - - public PgpImportExport(Context context, - ProgressDialogUpdater progress, KeychainServiceListener keychainListener) { - super(); - this.mContext = context; - this.mProgress = progress; - this.mKeychainServiceListener = keychainListener; - } - - public void updateProgress(int message, int current, int total) { - if (mProgress != null) { - mProgress.setProgress(message, current, total); - } - } - - public void updateProgress(String message, int current, int total) { - if (mProgress != null) { - mProgress.setProgress(message, current, total); - } - } - - public void updateProgress(int current, int total) { - if (mProgress != null) { - mProgress.setProgress(current, total); - } - } - - public boolean uploadKeyRingToServer(HkpKeyServer server, PGPPublicKeyRing keyring) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ArmoredOutputStream aos = null; - try { - aos = new ArmoredOutputStream(bos); - aos.write(keyring.getEncoded()); - aos.close(); - - String armoredKey = bos.toString("UTF-8"); - server.add(armoredKey); - - return true; - } catch (IOException e) { - return false; - } catch (AddKeyException e) { - // TODO: tell the user? - return false; - } finally { - try { - if (aos != null) { aos.close(); } - if (bos != null) { bos.close(); } - } catch (IOException e) { - } - } - } - - /** - * Imports keys from given data. If keyIds is given only those are imported - */ - public Bundle importKeyRings(List<ImportKeysListEntry> entries) - throws PgpGeneralException, PGPException, IOException { - Bundle returnData = new Bundle(); - - updateProgress(R.string.progress_importing, 0, 100); - - int newKeys = 0; - int oldKeys = 0; - int badKeys = 0; - - int position = 0; - try { - for (ImportKeysListEntry entry : entries) { - Object obj = PgpConversionHelper.BytesToPGPKeyRing(entry.getBytes()); - - if (obj instanceof PGPKeyRing) { - PGPKeyRing keyring = (PGPKeyRing) obj; - - int status = storeKeyRingInCache(keyring); - - if (status == Id.return_value.error) { - throw new PgpGeneralException( - mContext.getString(R.string.error_saving_keys)); - } - - // update the counts to display to the user at the end - if (status == Id.return_value.updated) { - ++oldKeys; - } else if (status == Id.return_value.ok) { - ++newKeys; - } else if (status == Id.return_value.bad) { - ++badKeys; - } - } else { - Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!"); - } - - position++; - updateProgress(position / entries.size() * 100, 100); - } - } catch (Exception e) { - Log.e(Constants.TAG, "Exception on parsing key file!", e); - } - - returnData.putInt(KeychainIntentService.RESULT_IMPORT_ADDED, newKeys); - returnData.putInt(KeychainIntentService.RESULT_IMPORT_UPDATED, oldKeys); - returnData.putInt(KeychainIntentService.RESULT_IMPORT_BAD, badKeys); - - return returnData; - } - - public Bundle exportKeyRings(ArrayList<Long> publicKeyRingMasterIds, - ArrayList<Long> secretKeyRingMasterIds, - OutputStream outStream) throws PgpGeneralException, - PGPException, IOException { - Bundle returnData = new Bundle(); - - int masterKeyIdsSize = publicKeyRingMasterIds.size() + secretKeyRingMasterIds.size(); - int progress = 0; - - updateProgress( - mContext.getResources().getQuantityString(R.plurals.progress_exporting_key, - masterKeyIdsSize), 0, 100); - - if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - throw new PgpGeneralException( - mContext.getString(R.string.error_external_storage_not_ready)); - } - // For each public masterKey id - for (long pubKeyMasterId : publicKeyRingMasterIds) { - progress++; - // Create an output stream - ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream); - arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext)); - - updateProgress(progress * 100 / masterKeyIdsSize, 100); - PGPPublicKeyRing publicKeyRing = - ProviderHelper.getPGPPublicKeyRing(mContext, pubKeyMasterId); - - if (publicKeyRing != null) { - publicKeyRing.encode(arOutStream); - } - - if (mKeychainServiceListener.hasServiceStopped()) { - arOutStream.close(); - return null; - } - - arOutStream.close(); - } - - // For each secret masterKey id - for (long secretKeyMasterId : secretKeyRingMasterIds) { - progress++; - // Create an output stream - ArmoredOutputStream arOutStream = new ArmoredOutputStream(outStream); - arOutStream.setHeader("Version", PgpHelper.getFullVersion(mContext)); - - updateProgress(progress * 100 / masterKeyIdsSize, 100); - PGPSecretKeyRing secretKeyRing = - ProviderHelper.getPGPSecretKeyRing(mContext, secretKeyMasterId); - - if (secretKeyRing != null) { - secretKeyRing.encode(arOutStream); - } - if (mKeychainServiceListener.hasServiceStopped()) { - arOutStream.close(); - return null; - } - - arOutStream.close(); - } - - returnData.putInt(KeychainIntentService.RESULT_EXPORT, masterKeyIdsSize); - - updateProgress(R.string.progress_done, 100, 100); - - return returnData; - } - - /** - * TODO: implement Id.return_value.updated as status when key already existed - */ - @SuppressWarnings("unchecked") - public int storeKeyRingInCache(PGPKeyRing keyring) { - int status = Integer.MIN_VALUE; // out of bounds value (Id.return_value.*) - try { - if (keyring instanceof PGPSecretKeyRing) { - PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring; - boolean save = true; - - for (PGPSecretKey testSecretKey : new IterableIterator<PGPSecretKey>( - secretKeyRing.getSecretKeys())) { - if (!testSecretKey.isMasterKey()) { - if (testSecretKey.isPrivateKeyEmpty()) { - // this is bad, something is very wrong... - save = false; - status = Id.return_value.bad; - } - } - } - - if (save) { - // TODO: preserve certifications - // (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?) - PGPPublicKeyRing newPubRing = null; - for (PGPPublicKey key : new IterableIterator<PGPPublicKey>( - secretKeyRing.getPublicKeys())) { - if (newPubRing == null) { - newPubRing = new PGPPublicKeyRing(key.getEncoded(), - new JcaKeyFingerprintCalculator()); - } - newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key); - } - if (newPubRing != null) { - ProviderHelper.saveKeyRing(mContext, newPubRing); - } - ProviderHelper.saveKeyRing(mContext, secretKeyRing); - // TODO: remove status returns, use exceptions! - status = Id.return_value.ok; - } - } else if (keyring instanceof PGPPublicKeyRing) { - PGPPublicKeyRing publicKeyRing = (PGPPublicKeyRing) keyring; - ProviderHelper.saveKeyRing(mContext, publicKeyRing); - // TODO: remove status returns, use exceptions! - status = Id.return_value.ok; - } - } catch (IOException e) { - status = Id.return_value.error; - } - - return status; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java deleted file mode 100644 index 4c786f555..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ /dev/null @@ -1,644 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.pgp; - -import android.content.Context; -import android.graphics.Color; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.style.ForegroundColorSpan; - -import org.spongycastle.bcpg.sig.KeyFlags; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.PGPSignatureSubpacketVector; -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.Log; - -import java.security.DigestException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.Locale; -import java.util.Vector; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class PgpKeyHelper { - - private static final Pattern USER_ID_PATTERN = Pattern.compile("^(.*?)(?: \\((.*)\\))?(?: <(.*)>)?$"); - - public static Date getCreationDate(PGPPublicKey key) { - return key.getCreationTime(); - } - - public static Date getCreationDate(PGPSecretKey key) { - return key.getPublicKey().getCreationTime(); - } - - @SuppressWarnings("unchecked") - public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) { - long cnt = 0; - if (keyRing == null) { - return null; - } - for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) { - if (cnt == num) { - return key; - } - cnt++; - } - - return null; - } - - @SuppressWarnings("unchecked") - public static Vector<PGPPublicKey> getEncryptKeys(PGPPublicKeyRing keyRing) { - Vector<PGPPublicKey> encryptKeys = new Vector<PGPPublicKey>(); - - for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) { - if (isEncryptionKey(key)) { - encryptKeys.add(key); - } - } - - return encryptKeys; - } - - @SuppressWarnings("unchecked") - public static Vector<PGPSecretKey> getSigningKeys(PGPSecretKeyRing keyRing) { - Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>(); - - for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) { - if (isSigningKey(key)) { - signingKeys.add(key); - } - } - - return signingKeys; - } - - @SuppressWarnings("unchecked") - public static Vector<PGPSecretKey> getCertificationKeys(PGPSecretKeyRing keyRing) { - Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>(); - - for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) { - if (isCertificationKey(key)) { - signingKeys.add(key); - } - } - - return signingKeys; - } - - public static Vector<PGPPublicKey> getUsableEncryptKeys(PGPPublicKeyRing keyRing) { - Vector<PGPPublicKey> usableKeys = new Vector<PGPPublicKey>(); - Vector<PGPPublicKey> encryptKeys = getEncryptKeys(keyRing); - PGPPublicKey masterKey = null; - for (int i = 0; i < encryptKeys.size(); ++i) { - PGPPublicKey key = encryptKeys.get(i); - if (!isExpired(key) && !key.isRevoked()) { - if (key.isMasterKey()) { - masterKey = key; - } else { - usableKeys.add(key); - } - } - } - if (masterKey != null) { - usableKeys.add(masterKey); - } - return usableKeys; - } - - public static boolean isExpired(PGPPublicKey key) { - Date creationDate = getCreationDate(key); - Date expiryDate = getExpiryDate(key); - Date now = new Date(); - if (now.compareTo(creationDate) >= 0 - && (expiryDate == null || now.compareTo(expiryDate) <= 0)) { - return false; - } - return true; - } - - public static Vector<PGPSecretKey> getUsableCertificationKeys(PGPSecretKeyRing keyRing) { - Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>(); - Vector<PGPSecretKey> signingKeys = getCertificationKeys(keyRing); - PGPSecretKey masterKey = null; - for (int i = 0; i < signingKeys.size(); ++i) { - PGPSecretKey key = signingKeys.get(i); - if (key.isMasterKey()) { - masterKey = key; - } else { - usableKeys.add(key); - } - } - if (masterKey != null) { - usableKeys.add(masterKey); - } - return usableKeys; - } - - public static Vector<PGPSecretKey> getUsableSigningKeys(PGPSecretKeyRing keyRing) { - Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>(); - Vector<PGPSecretKey> signingKeys = getSigningKeys(keyRing); - PGPSecretKey masterKey = null; - for (int i = 0; i < signingKeys.size(); ++i) { - PGPSecretKey key = signingKeys.get(i); - if (key.isMasterKey()) { - masterKey = key; - } else { - usableKeys.add(key); - } - } - if (masterKey != null) { - usableKeys.add(masterKey); - } - return usableKeys; - } - - public static Date getExpiryDate(PGPPublicKey key) { - Date creationDate = getCreationDate(key); - if (key.getValidDays() == 0) { - // no expiry - return null; - } - Calendar calendar = GregorianCalendar.getInstance(); - calendar.setTime(creationDate); - calendar.add(Calendar.DATE, key.getValidDays()); - - return calendar.getTime(); - } - - public static Date getExpiryDate(PGPSecretKey key) { - return getExpiryDate(key.getPublicKey()); - } - - public static PGPPublicKey getEncryptPublicKey(Context context, long masterKeyId) { - PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRing(context, masterKeyId); - if (keyRing == null) { - Log.e(Constants.TAG, "keyRing is null!"); - return null; - } - Vector<PGPPublicKey> encryptKeys = getUsableEncryptKeys(keyRing); - if (encryptKeys.size() == 0) { - Log.e(Constants.TAG, "encryptKeys is null!"); - return null; - } - return encryptKeys.get(0); - } - - public static PGPSecretKey getCertificationKey(Context context, long masterKeyId) { - PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId); - if (keyRing == null) { - return null; - } - Vector<PGPSecretKey> signingKeys = getUsableCertificationKeys(keyRing); - if (signingKeys.size() == 0) { - return null; - } - return signingKeys.get(0); - } - - public static PGPSecretKey getSigningKey(Context context, long masterKeyId) { - PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId); - if (keyRing == null) { - return null; - } - Vector<PGPSecretKey> signingKeys = getUsableSigningKeys(keyRing); - if (signingKeys.size() == 0) { - return null; - } - return signingKeys.get(0); - } - - @SuppressWarnings("unchecked") - public static String getMainUserId(PGPPublicKey key) { - for (String userId : new IterableIterator<String>(key.getUserIDs())) { - return userId; - } - return null; - } - - @SuppressWarnings("unchecked") - public static String getMainUserId(PGPSecretKey key) { - for (String userId : new IterableIterator<String>(key.getUserIDs())) { - return userId; - } - return null; - } - - public static String getMainUserIdSafe(Context context, PGPPublicKey key) { - String userId = getMainUserId(key); - if (userId == null || userId.equals("")) { - userId = context.getString(R.string.user_id_no_name); - } - return userId; - } - - public static String getMainUserIdSafe(Context context, PGPSecretKey key) { - String userId = getMainUserId(key); - if (userId == null || userId.equals("")) { - userId = context.getString(R.string.user_id_no_name); - } - return userId; - } - - public static int getKeyUsage(PGPSecretKey key) { - return getKeyUsage(key.getPublicKey()); - } - - @SuppressWarnings("unchecked") - private static int getKeyUsage(PGPPublicKey key) { - int usage = 0; - if (key.getVersion() >= 4) { - for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) { - if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) { - continue; - } - - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); - if (hashed != null) { - usage |= hashed.getKeyFlags(); - } - - PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); - if (unhashed != null) { - usage |= unhashed.getKeyFlags(); - } - } - } - return usage; - } - - @SuppressWarnings("unchecked") - public static boolean isEncryptionKey(PGPPublicKey key) { - if (!key.isEncryptionKey()) { - return false; - } - - if (key.getVersion() <= 3) { - // this must be true now - return key.isEncryptionKey(); - } - - // special cases - if (key.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) { - return true; - } - - if (key.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) { - return true; - } - - for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) { - if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) { - continue; - } - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); - - if (hashed != null - && (hashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) { - return true; - } - - PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); - - if (unhashed != null - && (unhashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) { - return true; - } - } - return false; - } - - public static boolean isEncryptionKey(PGPSecretKey key) { - return isEncryptionKey(key.getPublicKey()); - } - - @SuppressWarnings("unchecked") - public static boolean isSigningKey(PGPPublicKey key) { - if (key.getVersion() <= 3) { - return true; - } - - // special case - if (key.getAlgorithm() == PGPPublicKey.RSA_SIGN) { - return true; - } - - for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) { - if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) { - continue; - } - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); - - if (hashed != null && (hashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) { - return true; - } - - PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); - - if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) { - return true; - } - } - - return false; - } - - public static boolean isSigningKey(PGPSecretKey key) { - return isSigningKey(key.getPublicKey()); - } - - @SuppressWarnings("unchecked") - public static boolean isCertificationKey(PGPPublicKey key) { - if (key.getVersion() <= 3) { - return true; - } - - for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) { - if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) { - continue; - } - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); - - if (hashed != null && (hashed.getKeyFlags() & KeyFlags.CERTIFY_OTHER) != 0) { - return true; - } - - PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); - - if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.CERTIFY_OTHER) != 0) { - return true; - } - } - - return false; - } - - public static boolean isAuthenticationKey(PGPSecretKey key) { - return isAuthenticationKey(key.getPublicKey()); - } - - @SuppressWarnings("unchecked") - public static boolean isAuthenticationKey(PGPPublicKey key) { - if (key.getVersion() <= 3) { - return true; - } - - for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) { - if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) { - continue; - } - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); - - if (hashed != null && (hashed.getKeyFlags() & KeyFlags.AUTHENTICATION) != 0) { - return true; - } - - PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets(); - - if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.AUTHENTICATION) != 0) { - return true; - } - } - - return false; - } - - public static boolean isCertificationKey(PGPSecretKey key) { - return isCertificationKey(key.getPublicKey()); - } - - public static String getAlgorithmInfo(PGPPublicKey key) { - return getAlgorithmInfo(key.getAlgorithm(), key.getBitStrength()); - } - - public static String getAlgorithmInfo(PGPSecretKey key) { - return getAlgorithmInfo(key.getPublicKey()); - } - - public static String getAlgorithmInfo(int algorithm, int keySize) { - String algorithmStr; - - switch (algorithm) { - case PGPPublicKey.RSA_ENCRYPT: - case PGPPublicKey.RSA_GENERAL: - case PGPPublicKey.RSA_SIGN: { - algorithmStr = "RSA"; - break; - } - case PGPPublicKey.DSA: { - algorithmStr = "DSA"; - break; - } - - case PGPPublicKey.ELGAMAL_ENCRYPT: - case PGPPublicKey.ELGAMAL_GENERAL: { - algorithmStr = "ElGamal"; - break; - } - - default: { - algorithmStr = "Unknown"; - break; - } - } - if(keySize > 0) - return algorithmStr + ", " + keySize + " bit"; - else - return algorithmStr; - } - - /** - * Converts fingerprint to hex (optional: with whitespaces after 4 characters) - * <p/> - * Fingerprint is shown using lowercase characters. Studies have shown that humans can - * better differentiate between numbers and letters when letters are lowercase. - * - * @param fingerprint - * @return - */ - public static String convertFingerprintToHex(byte[] fingerprint) { - String hexString = Hex.toHexString(fingerprint); - - return hexString; - } - - /** - * Convert key id from long to 64 bit hex string - * <p/> - * V4: "The Key ID is the low-order 64 bits of the fingerprint" - * <p/> - * see http://tools.ietf.org/html/rfc4880#section-12.2 - * - * @param keyId - * @return - */ - public static String convertKeyIdToHex(long keyId) { - long upper = keyId >> 32; - if (upper == 0) { - // this is a short key id - return convertKeyIdToHexShort(keyId); - } - return "0x" + convertKeyIdToHex32bit(keyId >> 32) + convertKeyIdToHex32bit(keyId); - } - - public static String convertKeyIdToHexShort(long keyId) { - return "0x" + convertKeyIdToHex32bit(keyId); - } - - private static String convertKeyIdToHex32bit(long keyId) { - String hexString = Long.toHexString(keyId & 0xffffffffL).toLowerCase(Locale.US); - while (hexString.length() < 8) { - hexString = "0" + hexString; - } - return hexString; - } - - - public static SpannableStringBuilder colorizeFingerprint(String fingerprint) { - // split by 4 characters - fingerprint = fingerprint.replaceAll("(.{4})(?!$)", "$1 "); - - // add line breaks to have a consistent "image" that can be recognized - char[] chars = fingerprint.toCharArray(); - chars[24] = '\n'; - fingerprint = String.valueOf(chars); - - SpannableStringBuilder sb = new SpannableStringBuilder(fingerprint); - try { - // for each 4 characters of the fingerprint + 1 space - for (int i = 0; i < fingerprint.length(); i += 5) { - int spanEnd = Math.min(i + 4, fingerprint.length()); - String fourChars = fingerprint.substring(i, spanEnd); - - int raw = Integer.parseInt(fourChars, 16); - byte[] bytes = {(byte) ((raw >> 8) & 0xff - 128), (byte) (raw & 0xff - 128)}; - int[] color = getRgbForData(bytes); - int r = color[0]; - int g = color[1]; - int b = color[2]; - - // we cannot change black by multiplication, so adjust it to an almost-black grey, - // which will then be brightened to the minimal brightness level - if (r == 0 && g == 0 && b == 0) { - r = 1; - g = 1; - b = 1; - } - - // Convert rgb to brightness - double brightness = 0.2126 * r + 0.7152 * g + 0.0722 * b; - - // If a color is too dark to be seen on black, - // then brighten it up to a minimal brightness. - if (brightness < 80) { - double factor = 80.0 / brightness; - r = Math.min(255, (int) (r * factor)); - g = Math.min(255, (int) (g * factor)); - b = Math.min(255, (int) (b * factor)); - - // If it is too light, then darken it to a respective maximal brightness. - } else if (brightness > 180) { - double factor = 180.0 / brightness; - r = (int) (r * factor); - g = (int) (g * factor); - b = (int) (b * factor); - } - - // Create a foreground color with the 3 digest integers as RGB - // and then converting that int to hex to use as a color - sb.setSpan(new ForegroundColorSpan(Color.rgb(r, g, b)), - i, spanEnd, Spannable.SPAN_INCLUSIVE_INCLUSIVE); - } - } catch (Exception e) { - Log.e(Constants.TAG, "Colorization failed", e); - // if anything goes wrong, then just display the fingerprint without colour, - // instead of partially correct colour or wrong colours - return new SpannableStringBuilder(fingerprint); - } - - return sb; - } - - /** - * Converts the given bytes to a unique RGB color using SHA1 algorithm - * - * @param bytes - * @return an integer array containing 3 numeric color representations (Red, Green, Black) - * @throws java.security.NoSuchAlgorithmException - * @throws java.security.DigestException - */ - private static int[] getRgbForData(byte[] bytes) throws NoSuchAlgorithmException, DigestException { - MessageDigest md = MessageDigest.getInstance("SHA1"); - - md.update(bytes); - byte[] digest = md.digest(); - - int[] result = {((int) digest[0] + 256) % 256, - ((int) digest[1] + 256) % 256, - ((int) digest[2] + 256) % 256}; - return result; - } - - /** - * Splits userId string into naming part, email part, and comment part - * - * @param userId - * @return array with naming (0), email (1), comment (2) - */ - public static String[] splitUserId(String userId) { - String[] result = new String[]{null, null, null}; - - if (userId == null || userId.equals("")) { - return result; - } - - /* - * User ID matching: - * http://fiddle.re/t4p6f - * - * test cases: - * "Max Mustermann (this is a comment) <max@example.com>" - * "Max Mustermann <max@example.com>" - * "Max Mustermann (this is a comment)" - * "Max Mustermann [this is nothing]" - */ - Matcher matcher = USER_ID_PATTERN.matcher(userId); - if (matcher.matches()) { - result[0] = matcher.group(1); - result[1] = matcher.group(3); - result[2] = matcher.group(2); - } - - return result; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java deleted file mode 100644 index 48b959738..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ /dev/null @@ -1,769 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.pgp; - -import android.util.Pair; - -import org.spongycastle.bcpg.CompressionAlgorithmTags; -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; -import org.spongycastle.bcpg.sig.KeyFlags; -import org.spongycastle.jce.spec.ElGamalParameterSpec; -import org.spongycastle.openpgp.PGPEncryptedData; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPKeyPair; -import org.spongycastle.openpgp.PGPKeyRingGenerator; -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.PGPSignatureGenerator; -import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; -import org.spongycastle.openpgp.PGPSignatureSubpacketVector; -import org.spongycastle.openpgp.PGPUtil; -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.JcaPGPContentSignerBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; -import org.sufficientlysecure.keychain.service.SaveKeyringParcel; -import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.Primes; -import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SecureRandom; -import java.security.SignatureException; -import java.util.ArrayList; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.Iterator; -import java.util.List; -import java.util.TimeZone; - -/** This class is the single place where ALL operations that actually modify a PGP public or secret - * key take place. - * - * Note that no android specific stuff should be done here, ie no imports from com.android. - * - * All operations support progress reporting to a ProgressDialogUpdater passed on initialization. - * This indicator may be null. - * - */ -public class PgpKeyOperation { - private ProgressDialogUpdater mProgress; - - private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{ - SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192, - SymmetricKeyAlgorithmTags.AES_128, SymmetricKeyAlgorithmTags.CAST5, - SymmetricKeyAlgorithmTags.TRIPLE_DES}; - private static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{HashAlgorithmTags.SHA1, - HashAlgorithmTags.SHA256, HashAlgorithmTags.RIPEMD160}; - private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{ - CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2, - CompressionAlgorithmTags.ZIP}; - - public PgpKeyOperation(ProgressDialogUpdater progress) { - super(); - this.mProgress = progress; - } - - void updateProgress(int message, int current, int total) { - if (mProgress != null) { - mProgress.setProgress(message, current, total); - } - } - - void updateProgress(int current, int total) { - if (mProgress != null) { - mProgress.setProgress(current, total); - } - } - - /** - * Creates new secret key. - * - * @param algorithmChoice - * @param keySize - * @param passphrase - * @param isMasterKey - * @return A newly created PGPSecretKey - * @throws NoSuchAlgorithmException - * @throws PGPException - * @throws NoSuchProviderException - * @throws PgpGeneralMsgIdException - * @throws InvalidAlgorithmParameterException - */ - - // TODO: key flags? - public PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase, - boolean isMasterKey) - throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, - PgpGeneralMsgIdException, InvalidAlgorithmParameterException { - - if (keySize < 512) { - throw new PgpGeneralMsgIdException(R.string.error_key_size_minimum512bit); - } - - if (passphrase == null) { - passphrase = ""; - } - - int algorithm; - KeyPairGenerator keyGen; - - switch (algorithmChoice) { - case Id.choice.algorithm.dsa: { - keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME); - keyGen.initialize(keySize, new SecureRandom()); - algorithm = PGPPublicKey.DSA; - break; - } - - case Id.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"); - - ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g); - - keyGen.initialize(elParams); - algorithm = PGPPublicKey.ELGAMAL_ENCRYPT; - break; - } - - case Id.choice.algorithm.rsa: { - keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME); - keyGen.initialize(keySize, new SecureRandom()); - - algorithm = PGPPublicKey.RSA_GENERAL; - break; - } - - default: { - throw new PgpGeneralMsgIdException(R.string.error_unknown_algorithm_choice); - } - } - - // 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 PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(), - sha1Calc, isMasterKey, keyEncryptor); - } - - public PGPSecretKeyRing changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassphrase, - String newPassphrase) - throws IOException, PGPException, NoSuchProviderException { - - updateProgress(R.string.progress_building_key, 0, 100); - if (oldPassphrase == null) { - oldPassphrase = ""; - } - if (newPassphrase == null) { - newPassphrase = ""; - } - - PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword( - keyRing, - new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray()), - new JcePBESecretKeyEncryptorBuilder(keyRing.getSecretKey() - .getKeyEncryptionAlgorithm()).build(newPassphrase.toCharArray())); - - return newKeyRing; - - } - - private Pair<PGPSecretKeyRing, PGPPublicKeyRing> buildNewSecretKey( - ArrayList<String> userIds, ArrayList<PGPSecretKey> keys, - ArrayList<GregorianCalendar> keysExpiryDates, - ArrayList<Integer> keysUsages, - String newPassphrase, String oldPassphrase) - throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { - - int usageId = keysUsages.get(0); - boolean canSign; - String mainUserId = userIds.get(0); - - PGPSecretKey masterKey = keys.get(0); - - // this removes all userIds and certifications previously attached to the masterPublicKey - PGPPublicKey masterPublicKey = masterKey.getPublicKey(); - - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray()); - PGPPrivateKey masterPrivateKey = masterKey.extractPrivateKey(keyDecryptor); - - updateProgress(R.string.progress_certifying_master_key, 20, 100); - - for (String userId : userIds) { - PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( - masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA1) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); - - sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey); - - PGPSignature certification = sGen.generateCertification(userId, masterPublicKey); - masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, certification); - } - - PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey); - - PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator(); - PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator(); - - hashedPacketsGen.setKeyFlags(true, usageId); - - hashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS); - hashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS); - hashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS); - - if (keysExpiryDates.get(0) != null) { - GregorianCalendar creationDate = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - creationDate.setTime(masterPublicKey.getCreationTime()); - GregorianCalendar expiryDate = keysExpiryDates.get(0); - //note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c - //here we purposefully ignore partial days in each date - long type has no fractional part! - long numDays = (expiryDate.getTimeInMillis() / 86400000) - - (creationDate.getTimeInMillis() / 86400000); - if (numDays <= 0) { - throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation); - } - hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); - } else { - hashedPacketsGen.setKeyExpirationTime(false, 0); - // do this explicitly, although since we're rebuilding, - // this happens anyway - } - - updateProgress(R.string.progress_building_master_key, 30, 100); - - // define hashing and signing algos - PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get( - HashAlgorithmTags.SHA1); - PGPContentSignerBuilder certificationSignerBuilder = new JcaPGPContentSignerBuilder( - masterKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1); - - // Build key encrypter based on passphrase - PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( - PGPEncryptedData.CAST5, sha1Calc) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - newPassphrase.toCharArray()); - - PGPKeyRingGenerator keyGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, - masterKeyPair, mainUserId, sha1Calc, hashedPacketsGen.generate(), - unhashedPacketsGen.generate(), certificationSignerBuilder, keyEncryptor); - - updateProgress(R.string.progress_adding_sub_keys, 40, 100); - - for (int i = 1; i < keys.size(); ++i) { - updateProgress(40 + 40 * (i - 1) / (keys.size() - 1), 100); - - PGPSecretKey subKey = keys.get(i); - PGPPublicKey subPublicKey = subKey.getPublicKey(); - - PBESecretKeyDecryptor keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - oldPassphrase.toCharArray()); - PGPPrivateKey subPrivateKey = subKey.extractPrivateKey(keyDecryptor2); - - // TODO: now used without algorithm and creation time?! (APG 1) - PGPKeyPair subKeyPair = new PGPKeyPair(subPublicKey, subPrivateKey); - - hashedPacketsGen = new PGPSignatureSubpacketGenerator(); - unhashedPacketsGen = new PGPSignatureSubpacketGenerator(); - - usageId = keysUsages.get(i); - canSign = (usageId & KeyFlags.SIGN_DATA) > 0; //todo - separate function for this - if (canSign) { - Date todayDate = new Date(); //both sig times the same - // cross-certify signing keys - hashedPacketsGen.setSignatureCreationTime(false, todayDate); //set outer creation time - PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator(); - subHashedPacketsGen.setSignatureCreationTime(false, todayDate); //set inner creation time - PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( - subPublicKey.getAlgorithm(), PGPUtil.SHA1) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); - sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey); - sGen.setHashedSubpackets(subHashedPacketsGen.generate()); - PGPSignature certification = sGen.generateCertification(masterPublicKey, - subPublicKey); - unhashedPacketsGen.setEmbeddedSignature(false, certification); - } - hashedPacketsGen.setKeyFlags(false, usageId); - - if (keysExpiryDates.get(i) != null) { - GregorianCalendar creationDate = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - creationDate.setTime(subPublicKey.getCreationTime()); - GregorianCalendar expiryDate = keysExpiryDates.get(i); - //note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c - //here we purposefully ignore partial days in each date - long type has no fractional part! - long numDays = (expiryDate.getTimeInMillis() / 86400000) - - (creationDate.getTimeInMillis() / 86400000); - if (numDays <= 0) { - throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation); - } - hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); - } else { - hashedPacketsGen.setKeyExpirationTime(false, 0); - // do this explicitly, although since we're rebuilding, - // this happens anyway - } - - keyGen.addSubKey(subKeyPair, hashedPacketsGen.generate(), unhashedPacketsGen.generate()); - } - - PGPSecretKeyRing secretKeyRing = keyGen.generateSecretKeyRing(); - PGPPublicKeyRing publicKeyRing = keyGen.generatePublicKeyRing(); - - return new Pair<PGPSecretKeyRing, PGPPublicKeyRing>(secretKeyRing, publicKeyRing); - - } - - public Pair<PGPSecretKeyRing, PGPPublicKeyRing> buildSecretKey(PGPSecretKeyRing mKR, - PGPPublicKeyRing pKR, - SaveKeyringParcel saveParcel) - throws PgpGeneralMsgIdException, PGPException, SignatureException, IOException { - - updateProgress(R.string.progress_building_key, 0, 100); - PGPSecretKey masterKey = saveParcel.keys.get(0); - - if (saveParcel.oldPassphrase == null) { - saveParcel.oldPassphrase = ""; - } - if (saveParcel.newPassphrase == null) { - saveParcel.newPassphrase = ""; - } - - if (mKR == null) { - return buildNewSecretKey(saveParcel.userIDs, saveParcel.keys, saveParcel.keysExpiryDates, - saveParcel.keysUsages, saveParcel.newPassphrase, saveParcel.oldPassphrase); //new Keyring - } - - /* - IDs - NB This might not need to happen later, if we change the way the primary ID is chosen - remove deleted ids - if the primary ID changed we need to: - remove all of the IDs from the keyring, saving their certifications - add them all in again, updating certs of IDs which have changed - else - remove changed IDs and add in with new certs - - if the master key changed, we need to remove the primary ID certification, so we can add - the new one when it is generated, and they don't conflict - - Keys - remove deleted keys - if a key is modified, re-sign it - do we need to remove and add in? - - Todo - identify more things which need to be preserved - e.g. trust levels? - user attributes - */ - - if (saveParcel.deletedKeys != null) { - for (PGPSecretKey dKey : saveParcel.deletedKeys) { - mKR = PGPSecretKeyRing.removeSecretKey(mKR, dKey); - } - } - - masterKey = mKR.getSecretKey(); - PGPPublicKey masterPublicKey = masterKey.getPublicKey(); - - int usageId = saveParcel.keysUsages.get(0); - boolean canSign; - String mainUserId = saveParcel.userIDs.get(0); - - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(saveParcel.oldPassphrase.toCharArray()); - PGPPrivateKey masterPrivateKey = masterKey.extractPrivateKey(keyDecryptor); - - updateProgress(R.string.progress_certifying_master_key, 20, 100); - - boolean anyIDChanged = false; - for (String delID : saveParcel.deletedIDs) { - anyIDChanged = true; - masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, delID); - } - - int userIDIndex = 0; - - PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator(); - PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator(); - - hashedPacketsGen.setKeyFlags(true, usageId); - - hashedPacketsGen.setPreferredSymmetricAlgorithms(true, PREFERRED_SYMMETRIC_ALGORITHMS); - hashedPacketsGen.setPreferredHashAlgorithms(true, PREFERRED_HASH_ALGORITHMS); - hashedPacketsGen.setPreferredCompressionAlgorithms(true, PREFERRED_COMPRESSION_ALGORITHMS); - - if (saveParcel.keysExpiryDates.get(0) != null) { - GregorianCalendar creationDate = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - creationDate.setTime(masterPublicKey.getCreationTime()); - GregorianCalendar expiryDate = saveParcel.keysExpiryDates.get(0); - //note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c - //here we purposefully ignore partial days in each date - long type has no fractional part! - long numDays = (expiryDate.getTimeInMillis() / 86400000) - - (creationDate.getTimeInMillis() / 86400000); - if (numDays <= 0) { - throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation); - } - hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); - } else { - hashedPacketsGen.setKeyExpirationTime(false, 0); - // do this explicitly, although since we're rebuilding, - // this happens anyway - } - - if (saveParcel.primaryIDChanged || - !saveParcel.originalIDs.get(0).equals(saveParcel.userIDs.get(0))) { - anyIDChanged = true; - ArrayList<Pair<String, PGPSignature>> sigList = new ArrayList<Pair<String, PGPSignature>>(); - for (String userId : saveParcel.userIDs) { - String origID = saveParcel.originalIDs.get(userIDIndex); - if (origID.equals(userId) && !saveParcel.newIDs[userIDIndex] && - !userId.equals(saveParcel.originalPrimaryID) && userIDIndex != 0) { - Iterator<PGPSignature> origSigs = masterPublicKey.getSignaturesForID(origID); - // TODO: make sure this iterator only has signatures we are interested in - while (origSigs.hasNext()) { - PGPSignature origSig = origSigs.next(); - sigList.add(new Pair<String, PGPSignature>(origID, origSig)); - } - } else { - PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( - masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA1) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); - - sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey); - if (userIDIndex == 0) { - sGen.setHashedSubpackets(hashedPacketsGen.generate()); - sGen.setUnhashedSubpackets(unhashedPacketsGen.generate()); - } - PGPSignature certification = sGen.generateCertification(userId, masterPublicKey); - sigList.add(new Pair<String, PGPSignature>(userId, certification)); - } - if (!saveParcel.newIDs[userIDIndex]) { - masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, origID); - } - userIDIndex++; - } - for (Pair<String, PGPSignature> toAdd : sigList) { - masterPublicKey = - PGPPublicKey.addCertification(masterPublicKey, toAdd.first, toAdd.second); - } - } else { - for (String userId : saveParcel.userIDs) { - String origID = saveParcel.originalIDs.get(userIDIndex); - if (!origID.equals(userId) || saveParcel.newIDs[userIDIndex]) { - anyIDChanged = true; - PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( - masterPublicKey.getAlgorithm(), HashAlgorithmTags.SHA1) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); - - sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey); - if (userIDIndex == 0) { - sGen.setHashedSubpackets(hashedPacketsGen.generate()); - sGen.setUnhashedSubpackets(unhashedPacketsGen.generate()); - } - PGPSignature certification = sGen.generateCertification(userId, masterPublicKey); - if (!saveParcel.newIDs[userIDIndex]) { - masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, origID); - } - masterPublicKey = - PGPPublicKey.addCertification(masterPublicKey, userId, certification); - } - userIDIndex++; - } - } - - ArrayList<Pair<String, PGPSignature>> sigList = new ArrayList<Pair<String, PGPSignature>>(); - if (saveParcel.moddedKeys[0]) { - userIDIndex = 0; - for (String userId : saveParcel.userIDs) { - String origID = saveParcel.originalIDs.get(userIDIndex); - if (!(origID.equals(saveParcel.originalPrimaryID) && !saveParcel.primaryIDChanged)) { - Iterator<PGPSignature> sigs = masterPublicKey.getSignaturesForID(userId); - // TODO: make sure this iterator only has signatures we are interested in - while (sigs.hasNext()) { - PGPSignature sig = sigs.next(); - sigList.add(new Pair<String, PGPSignature>(userId, sig)); - } - } - masterPublicKey = PGPPublicKey.removeCertification(masterPublicKey, userId); - userIDIndex++; - } - anyIDChanged = true; - } - - //update the keyring with the new ID information - if (anyIDChanged) { - pKR = PGPPublicKeyRing.insertPublicKey(pKR, masterPublicKey); - mKR = PGPSecretKeyRing.replacePublicKeys(mKR, pKR); - } - - PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey); - - updateProgress(R.string.progress_building_master_key, 30, 100); - - // define hashing and signing algos - PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get( - HashAlgorithmTags.SHA1); - PGPContentSignerBuilder certificationSignerBuilder = new JcaPGPContentSignerBuilder( - masterKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1); - - // Build key encryptor based on old passphrase, as some keys may be unchanged - PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( - PGPEncryptedData.CAST5, sha1Calc) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - saveParcel.oldPassphrase.toCharArray()); - - //this generates one more signature than necessary... - PGPKeyRingGenerator keyGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, - masterKeyPair, mainUserId, sha1Calc, hashedPacketsGen.generate(), - unhashedPacketsGen.generate(), certificationSignerBuilder, keyEncryptor); - - for (int i = 1; i < saveParcel.keys.size(); ++i) { - updateProgress(40 + 50 * i / saveParcel.keys.size(), 100); - if (saveParcel.moddedKeys[i]) { - PGPSecretKey subKey = saveParcel.keys.get(i); - PGPPublicKey subPublicKey = subKey.getPublicKey(); - - PBESecretKeyDecryptor keyDecryptor2; - if (saveParcel.newKeys[i]) { - keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - "".toCharArray()); - } else { - keyDecryptor2 = new JcePBESecretKeyDecryptorBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - saveParcel.oldPassphrase.toCharArray()); - } - PGPPrivateKey subPrivateKey = subKey.extractPrivateKey(keyDecryptor2); - PGPKeyPair subKeyPair = new PGPKeyPair(subPublicKey, subPrivateKey); - - hashedPacketsGen = new PGPSignatureSubpacketGenerator(); - unhashedPacketsGen = new PGPSignatureSubpacketGenerator(); - - usageId = saveParcel.keysUsages.get(i); - canSign = (usageId & KeyFlags.SIGN_DATA) > 0; //todo - separate function for this - if (canSign) { - Date todayDate = new Date(); //both sig times the same - // cross-certify signing keys - hashedPacketsGen.setSignatureCreationTime(false, todayDate); //set outer creation time - PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator(); - subHashedPacketsGen.setSignatureCreationTime(false, todayDate); //set inner creation time - PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( - subPublicKey.getAlgorithm(), PGPUtil.SHA1) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); - sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey); - sGen.setHashedSubpackets(subHashedPacketsGen.generate()); - PGPSignature certification = sGen.generateCertification(masterPublicKey, - subPublicKey); - unhashedPacketsGen.setEmbeddedSignature(false, certification); - } - hashedPacketsGen.setKeyFlags(false, usageId); - - if (saveParcel.keysExpiryDates.get(i) != null) { - GregorianCalendar creationDate = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - creationDate.setTime(subPublicKey.getCreationTime()); - GregorianCalendar expiryDate = saveParcel.keysExpiryDates.get(i); - // note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c - // here we purposefully ignore partial days in each date - long type has - // no fractional part! - long numDays = (expiryDate.getTimeInMillis() / 86400000) - - (creationDate.getTimeInMillis() / 86400000); - if (numDays <= 0) { - throw new PgpGeneralMsgIdException(R.string.error_expiry_must_come_after_creation); - } - hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); - } else { - hashedPacketsGen.setKeyExpirationTime(false, 0); - // do this explicitly, although since we're rebuilding, - // this happens anyway - } - - keyGen.addSubKey(subKeyPair, hashedPacketsGen.generate(), unhashedPacketsGen.generate()); - // certifications will be discarded if the key is changed, because I think, for a start, - // they will be invalid. Binding certs are regenerated anyway, and other certs which - // need to be kept are on IDs and attributes - // TODO: don't let revoked keys be edited, other than removed - changing one would - // result in the revocation being wrong? - } - } - - PGPSecretKeyRing updatedSecretKeyRing = keyGen.generateSecretKeyRing(); - //finally, update the keyrings - Iterator<PGPSecretKey> itr = updatedSecretKeyRing.getSecretKeys(); - while (itr.hasNext()) { - PGPSecretKey theNextKey = itr.next(); - if ((theNextKey.isMasterKey() && saveParcel.moddedKeys[0]) || !theNextKey.isMasterKey()) { - mKR = PGPSecretKeyRing.insertSecretKey(mKR, theNextKey); - pKR = PGPPublicKeyRing.insertPublicKey(pKR, theNextKey.getPublicKey()); - } - } - - //replace lost IDs - if (saveParcel.moddedKeys[0]) { - masterPublicKey = mKR.getPublicKey(); - for (Pair<String, PGPSignature> toAdd : sigList) { - masterPublicKey = PGPPublicKey.addCertification(masterPublicKey, toAdd.first, toAdd.second); - } - pKR = PGPPublicKeyRing.insertPublicKey(pKR, masterPublicKey); - mKR = PGPSecretKeyRing.replacePublicKeys(mKR, pKR); - } - - // Build key encryptor based on new passphrase - PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder( - PGPEncryptedData.CAST5, sha1Calc) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - saveParcel.newPassphrase.toCharArray()); - - //update the passphrase - mKR = PGPSecretKeyRing.copyWithNewPassword(mKR, keyDecryptor, keyEncryptorNew); - - /* additional handy debug info - - Log.d(Constants.TAG, " ------- in private key -------"); - - for(String uid : new IterableIterator<String>(secretKeyRing.getPublicKey().getUserIDs())) { - for(PGPSignature sig : new IterableIterator<PGPSignature>( - secretKeyRing.getPublicKey().getSignaturesForID(uid))) { - Log.d(Constants.TAG, "sig: " + - PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid); - } - - } - - Log.d(Constants.TAG, " ------- in public key -------"); - - for(String uid : new IterableIterator<String>(publicKeyRing.getPublicKey().getUserIDs())) { - for(PGPSignature sig : new IterableIterator<PGPSignature>( - publicKeyRing.getPublicKey().getSignaturesForID(uid))) { - Log.d(Constants.TAG, "sig: " + - PgpKeyHelper.convertKeyIdToHex(sig.getKeyID()) + " for " + uid); - } - } - - */ - - return new Pair<PGPSecretKeyRing, PGPPublicKeyRing>(mKR, pKR); - - } - - /** - * Certify the given pubkeyid with the given masterkeyid. - * - * @param certificationKey Certifying key - * @param publicKey public key to certify - * @param userIds User IDs to certify, must not be null or empty - * @param passphrase Passphrase of the secret key - * @return A keyring with added certifications - */ - public PGPPublicKey certifyKey(PGPSecretKey certificationKey, PGPPublicKey publicKey, - List<String> userIds, String passphrase) - throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException, - PGPException, SignatureException { - - // create a signatureGenerator from the supplied masterKeyId and passphrase - PGPSignatureGenerator signatureGenerator; { - - if (certificationKey == null) { - throw new PgpGeneralMsgIdException(R.string.error_signature_failed); - } - - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); - PGPPrivateKey signaturePrivateKey = certificationKey.extractPrivateKey(keyDecryptor); - if (signaturePrivateKey == null) { - throw new PgpGeneralMsgIdException(R.string.error_could_not_extract_private_key); - } - - // TODO: SHA256 fixed? - JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( - certificationKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); - signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, signaturePrivateKey); - } - - { // supply signatureGenerator with a SubpacketVector - PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - PGPSignatureSubpacketVector packetVector = spGen.generate(); - signatureGenerator.setHashedSubpackets(packetVector); - } - - // fetch public key ring, add the certification and return it - for (String userId : new IterableIterator<String>(userIds.iterator())) { - PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey); - publicKey = PGPPublicKey.addCertification(publicKey, userId, sig); - } - - return publicKey; - } - - /** Simple static subclass that stores two values. - * - * This is only used to return a pair of values in one function above. We specifically don't use - * com.android.Pair to keep this class free from android dependencies. - */ - public static class Pair<K, V> { - public final K first; - public final V second; - public Pair(K first, V second) { - this.first = first; - this.second = second; - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java deleted file mode 100644 index a864a165d..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.pgp; - -import android.content.Context; - -import org.spongycastle.bcpg.ArmoredOutputStream; -import org.spongycastle.bcpg.BCPGOutputStream; -import org.spongycastle.openpgp.PGPCompressedDataGenerator; -import org.spongycastle.openpgp.PGPEncryptedDataGenerator; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPLiteralData; -import org.spongycastle.openpgp.PGPLiteralDataGenerator; -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.PGPSignatureGenerator; -import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; -import org.spongycastle.openpgp.PGPV3SignatureGenerator; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; -import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SignatureException; -import java.util.Date; - -/** - * This class uses a Builder pattern! - */ -public class PgpSignEncrypt { - private Context mContext; - private InputData mData; - private OutputStream mOutStream; - - private ProgressDialogUpdater mProgress; - private boolean mEnableAsciiArmorOutput; - private int mCompressionId; - private long[] mEncryptionKeyIds; - private String mSymmetricPassphrase; - private int mSymmetricEncryptionAlgorithm; - private long mSignatureKeyId; - private int mSignatureHashAlgorithm; - private boolean mSignatureForceV3; - private String mSignaturePassphrase; - - private PgpSignEncrypt(Builder builder) { - // private Constructor can only be called from Builder - this.mContext = builder.mContext; - this.mData = builder.mData; - this.mOutStream = builder.mOutStream; - - this.mProgress = builder.mProgress; - this.mEnableAsciiArmorOutput = builder.mEnableAsciiArmorOutput; - this.mCompressionId = builder.mCompressionId; - this.mEncryptionKeyIds = builder.mEncryptionKeyIds; - this.mSymmetricPassphrase = builder.mSymmetricPassphrase; - this.mSymmetricEncryptionAlgorithm = builder.mSymmetricEncryptionAlgorithm; - this.mSignatureKeyId = builder.mSignatureKeyId; - this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm; - this.mSignatureForceV3 = builder.mSignatureForceV3; - this.mSignaturePassphrase = builder.mSignaturePassphrase; - } - - public static class Builder { - // mandatory parameter - private Context mContext; - private InputData mData; - private OutputStream mOutStream; - - // optional - private ProgressDialogUpdater mProgress = null; - private boolean mEnableAsciiArmorOutput = false; - private int mCompressionId = Id.choice.compression.none; - private long[] mEncryptionKeyIds = null; - private String mSymmetricPassphrase = null; - private int mSymmetricEncryptionAlgorithm = 0; - private long mSignatureKeyId = Id.key.none; - private int mSignatureHashAlgorithm = 0; - private boolean mSignatureForceV3 = false; - private String mSignaturePassphrase = null; - - public Builder(Context context, InputData data, OutputStream outStream) { - this.mContext = context; - this.mData = data; - this.mOutStream = outStream; - } - - public Builder progress(ProgressDialogUpdater progress) { - this.mProgress = progress; - return this; - } - - public Builder enableAsciiArmorOutput(boolean enableAsciiArmorOutput) { - this.mEnableAsciiArmorOutput = enableAsciiArmorOutput; - return this; - } - - public Builder compressionId(int compressionId) { - this.mCompressionId = compressionId; - return this; - } - - public Builder encryptionKeyIds(long[] encryptionKeyIds) { - this.mEncryptionKeyIds = encryptionKeyIds; - return this; - } - - public Builder symmetricPassphrase(String symmetricPassphrase) { - this.mSymmetricPassphrase = symmetricPassphrase; - return this; - } - - public Builder symmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) { - this.mSymmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm; - return this; - } - - public Builder signatureKeyId(long signatureKeyId) { - this.mSignatureKeyId = signatureKeyId; - return this; - } - - public Builder signatureHashAlgorithm(int signatureHashAlgorithm) { - this.mSignatureHashAlgorithm = signatureHashAlgorithm; - return this; - } - - public Builder signatureForceV3(boolean signatureForceV3) { - this.mSignatureForceV3 = signatureForceV3; - return this; - } - - public Builder signaturePassphrase(String signaturePassphrase) { - this.mSignaturePassphrase = signaturePassphrase; - return this; - } - - public PgpSignEncrypt build() { - return new PgpSignEncrypt(this); - } - } - - public void updateProgress(int message, int current, int total) { - if (mProgress != null) { - mProgress.setProgress(message, current, total); - } - } - - public void updateProgress(int current, int total) { - if (mProgress != null) { - mProgress.setProgress(current, total); - } - } - - /** - * Signs and/or encrypts data based on parameters of class - * - * @throws IOException - * @throws PgpGeneralException - * @throws PGPException - * @throws NoSuchProviderException - * @throws NoSuchAlgorithmException - * @throws SignatureException - */ - public void execute() - throws IOException, PgpGeneralException, PGPException, NoSuchProviderException, - NoSuchAlgorithmException, SignatureException { - - boolean enableSignature = mSignatureKeyId != Id.key.none; - boolean enableEncryption = ((mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0) - || mSymmetricPassphrase != null); - boolean enableCompression = (enableEncryption && mCompressionId != Id.choice.compression.none); - - Log.d(Constants.TAG, "enableSignature:" + enableSignature - + "\nenableEncryption:" + enableEncryption - + "\nenableCompression:" + enableCompression - + "\nenableAsciiArmorOutput:" + mEnableAsciiArmorOutput); - - int signatureType; - if (mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) { - // for sign-only ascii text - signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT; - } else { - signatureType = PGPSignature.BINARY_DOCUMENT; - } - - ArmoredOutputStream armorOut = null; - OutputStream out; - if (mEnableAsciiArmorOutput) { - armorOut = new ArmoredOutputStream(mOutStream); - armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext)); - out = armorOut; - } else { - out = mOutStream; - } - - /* Get keys for signature generation for later usage */ - PGPSecretKey signingKey = null; - PGPSecretKeyRing signingKeyRing = null; - PGPPrivateKey signaturePrivateKey = null; - if (enableSignature) { - signingKeyRing = ProviderHelper.getPGPSecretKeyRingWithKeyId(mContext, mSignatureKeyId); - signingKey = PgpKeyHelper.getSigningKey(mContext, mSignatureKeyId); - if (signingKey == null) { - throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed)); - } - - if (mSignaturePassphrase == null) { - throw new PgpGeneralException( - mContext.getString(R.string.error_no_signature_passphrase)); - } - - updateProgress(R.string.progress_extracting_signature_key, 0, 100); - - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray()); - signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor); - if (signaturePrivateKey == null) { - throw new PgpGeneralException( - mContext.getString(R.string.error_could_not_extract_private_key)); - } - } - updateProgress(R.string.progress_preparing_streams, 5, 100); - - /* Initialize PGPEncryptedDataGenerator for later usage */ - PGPEncryptedDataGenerator cPk = null; - if (enableEncryption) { - // has Integrity packet enabled! - JcePGPDataEncryptorBuilder encryptorBuilder = - new JcePGPDataEncryptorBuilder(mSymmetricEncryptionAlgorithm) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME) - .setWithIntegrityPacket(true); - - cPk = new PGPEncryptedDataGenerator(encryptorBuilder); - - if (mSymmetricPassphrase != null) { - // Symmetric encryption - Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption"); - - JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator = - new JcePBEKeyEncryptionMethodGenerator(mSymmetricPassphrase.toCharArray()); - cPk.addMethod(symmetricEncryptionGenerator); - } else { - // Asymmetric encryption - for (long id : mEncryptionKeyIds) { - PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(mContext, id); - if (key != null) { - JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator = - new JcePublicKeyKeyEncryptionMethodGenerator(key); - cPk.addMethod(pubKeyEncryptionGenerator); - } - } - } - } - - /* Initialize signature generator object for later usage */ - PGPSignatureGenerator signatureGenerator = null; - PGPV3SignatureGenerator signatureV3Generator = null; - if (enableSignature) { - updateProgress(R.string.progress_preparing_signature, 10, 100); - - // content signer based on signing key algorithm and chosen hash algorithm - JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( - signingKey.getPublicKey().getAlgorithm(), mSignatureHashAlgorithm) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - if (mSignatureForceV3) { - signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder); - signatureV3Generator.init(signatureType, signaturePrivateKey); - } else { - signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); - signatureGenerator.init(signatureType, signaturePrivateKey); - - String userId = PgpKeyHelper.getMainUserId(signingKeyRing.getSecretKey()); - PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - spGen.setSignerUserID(false, userId); - signatureGenerator.setHashedSubpackets(spGen.generate()); - } - } - - PGPCompressedDataGenerator compressGen = null; - OutputStream pOut; - OutputStream encryptionOut = null; - BCPGOutputStream bcpgOut; - if (enableEncryption) { - /* actual encryption */ - - encryptionOut = cPk.open(out, new byte[1 << 16]); - - if (enableCompression) { - compressGen = new PGPCompressedDataGenerator(mCompressionId); - bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut)); - } else { - bcpgOut = new BCPGOutputStream(encryptionOut); - } - - if (enableSignature) { - if (mSignatureForceV3) { - signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut); - } else { - signatureGenerator.generateOnePassVersion(false).encode(bcpgOut); - } - } - - PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator(); - // file name not needed, so empty string - pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "", new Date(), - new byte[1 << 16]); - updateProgress(R.string.progress_encrypting, 20, 100); - - long progress = 0; - int n; - byte[] buffer = new byte[1 << 16]; - InputStream in = mData.getInputStream(); - while ((n = in.read(buffer)) > 0) { - pOut.write(buffer, 0, n); - - // update signature buffer if signature is requested - if (enableSignature) { - if (mSignatureForceV3) { - signatureV3Generator.update(buffer, 0, n); - } else { - signatureGenerator.update(buffer, 0, n); - } - } - - progress += n; - if (mData.getSize() != 0) { - updateProgress((int) (20 + (95 - 20) * progress / mData.getSize()), 100); - } - } - - literalGen.close(); - } else if (mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) { - /* sign-only of ascii text */ - - updateProgress(R.string.progress_signing, 40, 100); - - // write directly on armor output stream - armorOut.beginClearText(mSignatureHashAlgorithm); - - InputStream in = mData.getInputStream(); - final BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - - final byte[] newline = "\r\n".getBytes("UTF-8"); - - if (mSignatureForceV3) { - processLine(reader.readLine(), armorOut, signatureV3Generator); - } else { - processLine(reader.readLine(), armorOut, signatureGenerator); - } - - while (true) { - String line = reader.readLine(); - - if (line == null) { - armorOut.write(newline); - break; - } - - armorOut.write(newline); - - // update signature buffer with input line - if (mSignatureForceV3) { - signatureV3Generator.update(newline); - processLine(line, armorOut, signatureV3Generator); - } else { - signatureGenerator.update(newline); - processLine(line, armorOut, signatureGenerator); - } - } - - armorOut.endClearText(); - - pOut = new BCPGOutputStream(armorOut); - } else { - // TODO: implement sign-only for files! - pOut = null; - Log.e(Constants.TAG, "not supported!"); - } - - if (enableSignature) { - updateProgress(R.string.progress_generating_signature, 95, 100); - if (mSignatureForceV3) { - signatureV3Generator.generate().encode(pOut); - } else { - signatureGenerator.generate().encode(pOut); - } - } - - // closing outputs - // NOTE: closing needs to be done in the correct order! - // TODO: closing bcpgOut and pOut??? - if (enableEncryption) { - if (enableCompression) { - compressGen.close(); - } - - encryptionOut.close(); - } - if (mEnableAsciiArmorOutput) { - armorOut.close(); - } - - out.close(); - mOutStream.close(); - - updateProgress(R.string.progress_done, 100, 100); - } - - // TODO: merge this into execute method! - // TODO: allow binary input for this class - public void generateSignature() - throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException, - SignatureException { - - OutputStream out; - if (mEnableAsciiArmorOutput) { - // Ascii Armor (Radix-64) - ArmoredOutputStream armorOut = new ArmoredOutputStream(mOutStream); - armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext)); - out = armorOut; - } else { - out = mOutStream; - } - - if (mSignatureKeyId == 0) { - throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key)); - } - - PGPSecretKeyRing signingKeyRing = - ProviderHelper.getPGPSecretKeyRingWithKeyId(mContext, mSignatureKeyId); - PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(mContext, mSignatureKeyId); - if (signingKey == null) { - throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed)); - } - - if (mSignaturePassphrase == null) { - throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_passphrase)); - } - - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray()); - PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor); - if (signaturePrivateKey == null) { - throw new PgpGeneralException( - mContext.getString(R.string.error_could_not_extract_private_key)); - } - updateProgress(R.string.progress_preparing_streams, 0, 100); - - updateProgress(R.string.progress_preparing_signature, 30, 100); - - int type = PGPSignature.CANONICAL_TEXT_DOCUMENT; -// if (binary) { -// type = PGPSignature.BINARY_DOCUMENT; -// } - - // content signer based on signing key algorithm and chosen hash algorithm - JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey - .getPublicKey().getAlgorithm(), mSignatureHashAlgorithm) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - - PGPSignatureGenerator signatureGenerator = null; - PGPV3SignatureGenerator signatureV3Generator = null; - if (mSignatureForceV3) { - signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder); - signatureV3Generator.init(type, signaturePrivateKey); - } else { - signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); - signatureGenerator.init(type, signaturePrivateKey); - - PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - String userId = PgpKeyHelper.getMainUserId(signingKeyRing.getSecretKey()); - spGen.setSignerUserID(false, userId); - signatureGenerator.setHashedSubpackets(spGen.generate()); - } - - updateProgress(R.string.progress_signing, 40, 100); - - InputStream inStream = mData.getInputStream(); -// if (binary) { -// byte[] buffer = new byte[1 << 16]; -// int n = 0; -// while ((n = inStream.read(buffer)) > 0) { -// if (signatureForceV3) { -// signatureV3Generator.update(buffer, 0, n); -// } else { -// signatureGenerator.update(buffer, 0, n); -// } -// } -// } else { - final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream)); - final byte[] newline = "\r\n".getBytes("UTF-8"); - - String line; - while ((line = reader.readLine()) != null) { - if (mSignatureForceV3) { - processLine(line, null, signatureV3Generator); - signatureV3Generator.update(newline); - } else { - processLine(line, null, signatureGenerator); - signatureGenerator.update(newline); - } - } -// } - - BCPGOutputStream bOut = new BCPGOutputStream(out); - if (mSignatureForceV3) { - signatureV3Generator.generate().encode(bOut); - } else { - signatureGenerator.generate().encode(bOut); - } - out.close(); - mOutStream.close(); - - updateProgress(R.string.progress_done, 100, 100); - } - - - private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput, - final PGPSignatureGenerator pSignatureGenerator) - throws IOException, SignatureException { - - if (pLine == null) { - return; - } - - final char[] chars = pLine.toCharArray(); - int len = chars.length; - - while (len > 0) { - if (!Character.isWhitespace(chars[len - 1])) { - break; - } - len--; - } - - final byte[] data = pLine.substring(0, len).getBytes("UTF-8"); - - if (pArmoredOutput != null) { - pArmoredOutput.write(data); - } - pSignatureGenerator.update(data); - } - - private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput, - final PGPV3SignatureGenerator pSignatureGenerator) - throws IOException, SignatureException { - - if (pLine == null) { - return; - } - - final char[] chars = pLine.toCharArray(); - int len = chars.length; - - while (len > 0) { - if (!Character.isWhitespace(chars[len - 1])) { - break; - } - len--; - } - - final byte[] data = pLine.substring(0, len).getBytes("UTF-8"); - - if (pArmoredOutput != null) { - pArmoredOutput.write(data); - } - pSignatureGenerator.update(data); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java deleted file mode 100644 index 5bb1665b6..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpToX509.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.pgp; - -import org.spongycastle.asn1.DERObjectIdentifier; -import org.spongycastle.asn1.x509.AuthorityKeyIdentifier; -import org.spongycastle.asn1.x509.BasicConstraints; -import org.spongycastle.asn1.x509.GeneralName; -import org.spongycastle.asn1.x509.GeneralNames; -import org.spongycastle.asn1.x509.SubjectKeyIdentifier; -import org.spongycastle.asn1.x509.X509Extensions; -import org.spongycastle.asn1.x509.X509Name; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.x509.X509V3CertificateGenerator; -import org.spongycastle.x509.extension.AuthorityKeyIdentifierStructure; -import org.spongycastle.x509.extension.SubjectKeyIdentifierStructure; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SignatureException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.text.DateFormat; -import java.util.Date; -import java.util.Iterator; -import java.util.Vector; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; - -public class PgpToX509 { - public static final String DN_COMMON_PART_O = "OpenPGP to X.509 Bridge"; - public static final String DN_COMMON_PART_OU = "OpenPGP Keychain cert"; - - /** - * Creates a self-signed certificate from a public and private key. The (critical) key-usage - * extension is set up with: digital signature, non-repudiation, key-encipherment, key-agreement - * and certificate-signing. The (non-critical) Netscape extension is set up with: SSL client and - * S/MIME. A URI subjectAltName may also be set up. - * - * @param pubKey public key - * @param privKey private key - * @param subject subject (and issuer) DN for this certificate, RFC 2253 format preferred. - * @param startDate date from which the certificate will be valid (defaults to current date and time - * if null) - * @param endDate date until which the certificate will be valid (defaults to current date and time - * if null) * - * @param subjAltNameURI URI to be placed in subjectAltName - * @return self-signed certificate - * @throws InvalidKeyException - * @throws SignatureException - * @throws NoSuchAlgorithmException - * @throws IllegalStateException - * @throws NoSuchProviderException - * @throws CertificateException - * @throws Exception - * @author Bruno Harbulot - */ - public static X509Certificate createSelfSignedCert( - PublicKey pubKey, PrivateKey privKey, X509Name subject, Date startDate, Date endDate, - String subjAltNameURI) - throws InvalidKeyException, IllegalStateException, NoSuchAlgorithmException, - SignatureException, CertificateException, NoSuchProviderException { - - X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator(); - - certGenerator.reset(); - /* - * Sets up the subject distinguished name. Since it's a self-signed certificate, issuer and - * subject are the same. - */ - certGenerator.setIssuerDN(subject); - certGenerator.setSubjectDN(subject); - - /* - * Sets up the validity dates. - */ - if (startDate == null) { - startDate = new Date(System.currentTimeMillis()); - } - certGenerator.setNotBefore(startDate); - if (endDate == null) { - endDate = new Date(startDate.getTime() + (365L * 24L * 60L * 60L * 1000L)); - Log.d(Constants.TAG, "end date is=" + DateFormat.getDateInstance().format(endDate)); - } - - certGenerator.setNotAfter(endDate); - - /* - * The serial-number of this certificate is 1. It makes sense because it's self-signed. - */ - certGenerator.setSerialNumber(BigInteger.ONE); - /* - * Sets the public-key to embed in this certificate. - */ - certGenerator.setPublicKey(pubKey); - /* - * Sets the signature algorithm. - */ - String pubKeyAlgorithm = pubKey.getAlgorithm(); - if (pubKeyAlgorithm.equals("DSA")) { - certGenerator.setSignatureAlgorithm("SHA1WithDSA"); - } else if (pubKeyAlgorithm.equals("RSA")) { - certGenerator.setSignatureAlgorithm("SHA1WithRSAEncryption"); - } else { - RuntimeException re = new RuntimeException("Algorithm not recognised: " - + pubKeyAlgorithm); - Log.e(Constants.TAG, re.getMessage(), re); - throw re; - } - - /* - * Adds the Basic Constraint (CA: true) extension. - */ - certGenerator.addExtension(X509Extensions.BasicConstraints, true, - new BasicConstraints(true)); - - /* - * Adds the subject key identifier extension. - */ - SubjectKeyIdentifier subjectKeyIdentifier = new SubjectKeyIdentifierStructure(pubKey); - certGenerator - .addExtension(X509Extensions.SubjectKeyIdentifier, false, subjectKeyIdentifier); - - /* - * Adds the authority key identifier extension. - */ - AuthorityKeyIdentifier authorityKeyIdentifier = new AuthorityKeyIdentifierStructure(pubKey); - certGenerator.addExtension(X509Extensions.AuthorityKeyIdentifier, false, - authorityKeyIdentifier); - - /* - * Adds the subject alternative-name extension. - */ - if (subjAltNameURI != null) { - GeneralNames subjectAltNames = new GeneralNames(new GeneralName( - GeneralName.uniformResourceIdentifier, subjAltNameURI)); - certGenerator.addExtension(X509Extensions.SubjectAlternativeName, false, - subjectAltNames); - } - - /* - * Creates and sign this certificate with the private key corresponding to the public key of - * the certificate (hence the name "self-signed certificate"). - */ - X509Certificate cert = certGenerator.generate(privKey); - - /* - * Checks that this certificate has indeed been correctly signed. - */ - cert.verify(pubKey); - - return cert; - } - - /** - * Creates a self-signed certificate from a PGP Secret Key. - * - * @param pgpSecKey PGP Secret Key (from which one can extract the public and private - * keys and other attributes). - * @param pgpPrivKey PGP Private Key corresponding to the Secret Key (password callbacks - * should be done before calling this method) - * @param subjAltNameURI optional URI to embed in the subject alternative-name - * @return self-signed certificate - * @throws PGPException - * @throws NoSuchProviderException - * @throws InvalidKeyException - * @throws NoSuchAlgorithmException - * @throws SignatureException - * @throws CertificateException - * @author Bruno Harbulot - */ - public static X509Certificate createSelfSignedCert( - PGPSecretKey pgpSecKey, PGPPrivateKey pgpPrivKey, String subjAltNameURI) - throws PGPException, NoSuchProviderException, InvalidKeyException, NoSuchAlgorithmException, - SignatureException, CertificateException { - // get public key from secret key - PGPPublicKey pgpPubKey = pgpSecKey.getPublicKey(); - - // LOGGER.info("Key ID: " + Long.toHexString(pgpPubKey.getKeyID() & 0xffffffffL)); - - /* - * The X.509 Name to be the subject DN is prepared. The CN is extracted from the Secret Key - * user ID. - */ - Vector<DERObjectIdentifier> x509NameOids = new Vector<DERObjectIdentifier>(); - Vector<String> x509NameValues = new Vector<String>(); - - x509NameOids.add(X509Name.O); - x509NameValues.add(DN_COMMON_PART_O); - - x509NameOids.add(X509Name.OU); - x509NameValues.add(DN_COMMON_PART_OU); - - for (@SuppressWarnings("unchecked") - Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserIDs(); it.hasNext(); ) { - Object attrib = it.next(); - x509NameOids.add(X509Name.CN); - x509NameValues.add("CryptoCall"); - // x509NameValues.add(attrib.toString()); - } - - /* - * Currently unused. - */ - Log.d(Constants.TAG, "User attributes: "); - for (@SuppressWarnings("unchecked") - Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserAttributes(); it.hasNext(); ) { - Object attrib = it.next(); - Log.d(Constants.TAG, " - " + attrib + " -- " + attrib.getClass()); - } - - X509Name x509name = new X509Name(x509NameOids, x509NameValues); - - Log.d(Constants.TAG, "Subject DN: " + x509name); - - /* - * To check the signature from the certificate on the recipient side, the creation time - * needs to be embedded in the certificate. It seems natural to make this creation time be - * the "not-before" date of the X.509 certificate. Unlimited PGP keys have a validity of 0 - * second. In this case, the "not-after" date will be the same as the not-before date. This - * is something that needs to be checked by the service receiving this certificate. - */ - Date creationTime = pgpPubKey.getCreationTime(); - Log.d(Constants.TAG, - "pgp pub key creation time=" + DateFormat.getDateInstance().format(creationTime)); - Log.d(Constants.TAG, "pgp valid seconds=" + pgpPubKey.getValidSeconds()); - Date validTo = null; - if (pgpPubKey.getValidSeconds() > 0) { - validTo = new Date(creationTime.getTime() + 1000L * pgpPubKey.getValidSeconds()); - } - - X509Certificate selfSignedCert = createSelfSignedCert( - pgpPubKey.getKey(Constants.BOUNCY_CASTLE_PROVIDER_NAME), pgpPrivKey.getKey(), - x509name, creationTime, validTo, subjAltNameURI); - - return selfSignedCert; - } - - /** - * This is a password callback handler that will fill in a password automatically. Useful to - * configure passwords in advance, but should be used with caution depending on how much you - * allow passwords to be stored within your application. - * - * @author Bruno Harbulot. - */ - public static final class PredefinedPasswordCallbackHandler implements CallbackHandler { - - private char[] mPassword; - private String mPrompt; - - public PredefinedPasswordCallbackHandler(String password) { - this(password == null ? null : password.toCharArray(), null); - } - - public PredefinedPasswordCallbackHandler(char[] password) { - this(password, null); - } - - public PredefinedPasswordCallbackHandler(String password, String prompt) { - this(password == null ? null : password.toCharArray(), prompt); - } - - public PredefinedPasswordCallbackHandler(char[] password, String prompt) { - this.mPassword = password; - this.mPrompt = prompt; - } - - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - for (Callback callback : callbacks) { - if (callback instanceof PasswordCallback) { - PasswordCallback pwCallback = (PasswordCallback) callback; - if ((this.mPrompt == null) || (this.mPrompt.equals(pwCallback.getPrompt()))) { - pwCallback.setPassword(this.mPassword); - } - } else { - throw new UnsupportedCallbackException(callback, "Unrecognised callback."); - } - } - } - - protected final Object clone() throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java deleted file mode 100644 index 23c4bbbd9..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/NoAsymmetricEncryptionException.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.pgp.exception; - -public class NoAsymmetricEncryptionException extends Exception { - static final long serialVersionUID = 0xf812773343L; - - public NoAsymmetricEncryptionException() { - super(); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java deleted file mode 100644 index 418445367..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.pgp.exception; - -public class PgpGeneralException extends Exception { - static final long serialVersionUID = 0xf812773342L; - - public PgpGeneralException(String message) { - super(message); - } - public PgpGeneralException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java deleted file mode 100644 index caa7842db..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/exception/PgpGeneralMsgIdException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.pgp.exception; - -import android.content.Context; - -public class PgpGeneralMsgIdException extends Exception { - static final long serialVersionUID = 0xf812773343L; - - private final int mMessageId; - - public PgpGeneralMsgIdException(int messageId) { - super("msg[" + messageId + "]"); - mMessageId = messageId; - } - - public PgpGeneralException getContextualized(Context context) { - return new PgpGeneralException(context.getString(mMessageId), this); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java deleted file mode 100644 index fc25faecd..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.provider; - -import android.net.Uri; -import android.provider.BaseColumns; - -import org.sufficientlysecure.keychain.Constants; - -public class KeychainContract { - - interface KeyRingsColumns { - String MASTER_KEY_ID = "master_key_id"; // not a database id - String KEY_RING_DATA = "key_ring_data"; // PGPPublicKeyRing / PGPSecretKeyRing blob - } - - interface KeysColumns { - String MASTER_KEY_ID = "master_key_id"; // not a database id - String RANK = "rank"; - - String KEY_ID = "key_id"; // not a database id - String ALGORITHM = "algorithm"; - String FINGERPRINT = "fingerprint"; - - String KEY_SIZE = "key_size"; - String CAN_SIGN = "can_sign"; - String CAN_ENCRYPT = "can_encrypt"; - String CAN_CERTIFY = "can_certify"; - String IS_REVOKED = "is_revoked"; - - String CREATION = "creation"; - String EXPIRY = "expiry"; - } - - interface UserIdsColumns { - String MASTER_KEY_ID = "master_key_id"; // foreign key to key_rings._ID - String USER_ID = "user_id"; // not a database id - String RANK = "rank"; // ONLY used for sorting! no key, no nothing! - String IS_PRIMARY = "is_primary"; - String IS_REVOKED = "is_revoked"; - } - - interface CertsColumns { - String MASTER_KEY_ID = "master_key_id"; - String RANK = "rank"; - String KEY_ID_CERTIFIER = "key_id_certifier"; - String TYPE = "type"; - String VERIFIED = "verified"; - String CREATION = "creation"; - String DATA = "data"; - } - - interface ApiAppsColumns { - String PACKAGE_NAME = "package_name"; - String PACKAGE_SIGNATURE = "package_signature"; - } - - interface ApiAppsAccountsColumns { - String ACCOUNT_NAME = "account_name"; - String KEY_ID = "key_id"; // not a database id - String ENCRYPTION_ALGORITHM = "encryption_algorithm"; - String HASH_ALORITHM = "hash_algorithm"; - String COMPRESSION = "compression"; - String PACKAGE_NAME = "package_name"; // foreign key to api_apps.package_name - } - - public static final class KeyTypes { - public static final int PUBLIC = 0; - public static final int SECRET = 1; - } - - public static final String CONTENT_AUTHORITY = Constants.PACKAGE_NAME + ".provider"; - - private static final Uri BASE_CONTENT_URI_INTERNAL = Uri - .parse("content://" + CONTENT_AUTHORITY); - - public static final String BASE_KEY_RINGS = "key_rings"; - public static final String BASE_DATA = "data"; - - public static final String PATH_UNIFIED = "unified"; - - public static final String PATH_FIND = "find"; - public static final String PATH_BY_EMAIL = "email"; - public static final String PATH_BY_SUBKEY = "subkey"; - - public static final String PATH_PUBLIC = "public"; - public static final String PATH_SECRET = "secret"; - public static final String PATH_USER_IDS = "user_ids"; - public static final String PATH_KEYS = "keys"; - public static final String PATH_CERTS = "certs"; - - public static final String BASE_API_APPS = "api_apps"; - public static final String PATH_ACCOUNTS = "accounts"; - - public static class KeyRings implements BaseColumns, KeysColumns, UserIdsColumns { - public static final String MASTER_KEY_ID = KeysColumns.MASTER_KEY_ID; - public static final String IS_REVOKED = KeysColumns.IS_REVOKED; - public static final String VERIFIED = CertsColumns.VERIFIED; - public static final String HAS_SECRET = "has_secret"; - - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_KEY_RINGS).build(); - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring"; - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring"; - - public static Uri buildUnifiedKeyRingsUri() { - return CONTENT_URI.buildUpon().appendPath(PATH_UNIFIED).build(); - } - - public static Uri buildGenericKeyRingUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).build(); - } - public static Uri buildUnifiedKeyRingUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_UNIFIED).build(); - } - public static Uri buildUnifiedKeyRingUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_UNIFIED).build(); - } - - public static Uri buildUnifiedKeyRingsFindByEmailUri(String email) { - return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_EMAIL).appendPath(email).build(); - } - public static Uri buildUnifiedKeyRingsFindBySubkeyUri(String subkey) { - return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_SUBKEY).appendPath(subkey).build(); - } - - } - - public static class KeyRingData implements KeyRingsColumns, BaseColumns { - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_KEY_RINGS).build(); - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring_data"; - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring_data"; - - public static Uri buildPublicKeyRingUri() { - return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).build(); - } - public static Uri buildPublicKeyRingUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_PUBLIC).build(); - } - public static Uri buildPublicKeyRingUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_PUBLIC).build(); - } - - public static Uri buildSecretKeyRingUri() { - return CONTENT_URI.buildUpon().appendPath(PATH_SECRET).build(); - } - public static Uri buildSecretKeyRingUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_SECRET).build(); - } - public static Uri buildSecretKeyRingUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_SECRET).build(); - } - - } - - public static class Keys implements KeysColumns, BaseColumns { - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_KEY_RINGS).build(); - - /** - * Use if multiple items get returned - */ - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key"; - - /** - * Use if a single item is returned - */ - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key"; - - public static Uri buildKeysUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_KEYS).build(); - } - public static Uri buildKeysUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_KEYS).build(); - } - - } - - public static class UserIds implements UserIdsColumns, BaseColumns { - public static final String VERIFIED = "verified"; - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_KEY_RINGS).build(); - - /** - * Use if multiple items get returned - */ - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.user_id"; - - /** - * Use if a single item is returned - */ - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.user_id"; - - public static Uri buildUserIdsUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_USER_IDS).build(); - } - public static Uri buildUserIdsUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_USER_IDS).build(); - } - } - - public static class ApiApps implements ApiAppsColumns, BaseColumns { - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_API_APPS).build(); - - /** - * Use if multiple items get returned - */ - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.api_apps"; - - /** - * Use if a single item is returned - */ - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.api_app"; - - public static Uri buildByPackageNameUri(String packageName) { - return CONTENT_URI.buildUpon().appendEncodedPath(packageName).build(); - } - } - - public static class ApiAccounts implements ApiAppsAccountsColumns, BaseColumns { - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_API_APPS).build(); - - /** - * Use if multiple items get returned - */ - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.api_app.accounts"; - - /** - * Use if a single item is returned - */ - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.api_app.account"; - - public static Uri buildBaseUri(String packageName) { - return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendPath(PATH_ACCOUNTS) - .build(); - } - - public static Uri buildByPackageAndAccountUri(String packageName, String accountName) { - return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendPath(PATH_ACCOUNTS) - .appendEncodedPath(accountName).build(); - } - } - - public static class Certs implements CertsColumns, BaseColumns { - public static final String USER_ID = UserIdsColumns.USER_ID; - public static final String SIGNER_UID = "signer_user_id"; - - public static final int VERIFIED_SECRET = 1; - public static final int VERIFIED_SELF = 2; - - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_KEY_RINGS).build(); - - public static Uri buildCertsUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_CERTS).build(); - } - public static Uri buildCertsSpecificUri(String masterKeyId, String rank, String certifier) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_CERTS).appendPath(rank).appendPath(certifier).build(); - } - public static Uri buildCertsUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_CERTS).build(); - } - - } - - public static class DataStream { - public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() - .appendPath(BASE_DATA).build(); - - public static Uri buildDataStreamUri(String streamFilename) { - return CONTENT_URI.buildUpon().appendPath(streamFilename).build(); - } - } - - private KeychainContract() { - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java deleted file mode 100644 index 8674ad94b..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.provider; - -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.provider.BaseColumns; - -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsAccountsColumns; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns; -import org.sufficientlysecure.keychain.provider.KeychainContract.CertsColumns; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; - -public class KeychainDatabase extends SQLiteOpenHelper { - private static final String DATABASE_NAME = "openkeychain.db"; - private static final int DATABASE_VERSION = 1; - static Boolean apgHack = false; - - public interface Tables { - String KEY_RINGS_PUBLIC = "keyrings_public"; - String KEY_RINGS_SECRET = "keyrings_secret"; - String KEYS = "keys"; - String USER_IDS = "user_ids"; - String CERTS = "certs"; - String API_APPS = "api_apps"; - String API_ACCOUNTS = "api_accounts"; - } - - private static final String CREATE_KEYRINGS_PUBLIC = - "CREATE TABLE IF NOT EXISTS keyrings_public (" - + KeyRingsColumns.MASTER_KEY_ID + " INTEGER PRIMARY KEY," - + KeyRingsColumns.KEY_RING_DATA + " BLOB" - + ")"; - - private static final String CREATE_KEYRINGS_SECRET = - "CREATE TABLE IF NOT EXISTS keyrings_secret (" - + KeyRingsColumns.MASTER_KEY_ID + " INTEGER PRIMARY KEY," - + KeyRingsColumns.KEY_RING_DATA + " BLOB," - + "FOREIGN KEY(" + KeyRingsColumns.MASTER_KEY_ID + ") " - + "REFERENCES keyrings_public(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE" - + ")"; - - private static final String CREATE_KEYS = - "CREATE TABLE IF NOT EXISTS " + Tables.KEYS + " (" - + KeysColumns.MASTER_KEY_ID + " INTEGER, " - + KeysColumns.RANK + " INTEGER, " - - + KeysColumns.KEY_ID + " INTEGER, " - + KeysColumns.KEY_SIZE + " INTEGER, " - + KeysColumns.ALGORITHM + " INTEGER, " - + KeysColumns.FINGERPRINT + " BLOB, " - - + KeysColumns.CAN_CERTIFY + " BOOLEAN, " - + KeysColumns.CAN_SIGN + " BOOLEAN, " - + KeysColumns.CAN_ENCRYPT + " BOOLEAN, " - + KeysColumns.IS_REVOKED + " BOOLEAN, " - - + KeysColumns.CREATION + " INTEGER, " - + KeysColumns.EXPIRY + " INTEGER, " - - + "PRIMARY KEY(" + KeysColumns.MASTER_KEY_ID + ", " + KeysColumns.RANK + ")," - + "FOREIGN KEY(" + KeysColumns.MASTER_KEY_ID + ") REFERENCES " - + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE" - + ")"; - - private static final String CREATE_USER_IDS = - "CREATE TABLE IF NOT EXISTS " + Tables.USER_IDS + "(" - + UserIdsColumns.MASTER_KEY_ID + " INTEGER, " - + UserIdsColumns.USER_ID + " CHARMANDER, " - - + UserIdsColumns.IS_PRIMARY + " BOOLEAN, " - + UserIdsColumns.IS_REVOKED + " BOOLEAN, " - + UserIdsColumns.RANK+ " INTEGER, " - - + "PRIMARY KEY(" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.USER_ID + "), " - + "UNIQUE (" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.RANK + "), " - + "FOREIGN KEY(" + UserIdsColumns.MASTER_KEY_ID + ") REFERENCES " - + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE" - + ")"; - - private static final String CREATE_CERTS = - "CREATE TABLE IF NOT EXISTS " + Tables.CERTS + "(" - + CertsColumns.MASTER_KEY_ID + " INTEGER," - + CertsColumns.RANK + " INTEGER, " // rank of certified uid - - + CertsColumns.KEY_ID_CERTIFIER + " INTEGER, " // certifying key - + CertsColumns.TYPE + " INTEGER, " - + CertsColumns.VERIFIED + " INTEGER, " - + CertsColumns.CREATION + " INTEGER, " - - + CertsColumns.DATA + " BLOB, " - - + "PRIMARY KEY(" + CertsColumns.MASTER_KEY_ID + ", " + CertsColumns.RANK + ", " - + CertsColumns.KEY_ID_CERTIFIER + "), " - + "FOREIGN KEY(" + CertsColumns.MASTER_KEY_ID + ") REFERENCES " - + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE," - + "FOREIGN KEY(" + CertsColumns.MASTER_KEY_ID + ", " + CertsColumns.RANK + ") REFERENCES " - + Tables.USER_IDS + "(" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.RANK + ") ON DELETE CASCADE" - + ")"; - - private static final String CREATE_API_APPS = "CREATE TABLE IF NOT EXISTS " + Tables.API_APPS - + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " - + ApiAppsColumns.PACKAGE_NAME + " TEXT NOT NULL UNIQUE, " - + ApiAppsColumns.PACKAGE_SIGNATURE + " BLOB)"; - - private static final String CREATE_API_APPS_ACCOUNTS = "CREATE TABLE IF NOT EXISTS " + Tables.API_ACCOUNTS - + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " - + ApiAppsAccountsColumns.ACCOUNT_NAME + " TEXT NOT NULL, " - + ApiAppsAccountsColumns.KEY_ID + " INT64, " - + ApiAppsAccountsColumns.ENCRYPTION_ALGORITHM + " INTEGER, " - + ApiAppsAccountsColumns.HASH_ALORITHM + " INTEGER, " - + ApiAppsAccountsColumns.COMPRESSION + " INTEGER, " - + ApiAppsAccountsColumns.PACKAGE_NAME + " TEXT NOT NULL, " - + "UNIQUE(" + ApiAppsAccountsColumns.ACCOUNT_NAME + ", " - + ApiAppsAccountsColumns.PACKAGE_NAME + "), " - + "FOREIGN KEY(" + ApiAppsAccountsColumns.PACKAGE_NAME + ") REFERENCES " - + Tables.API_APPS + "(" + ApiAppsColumns.PACKAGE_NAME + ") ON DELETE CASCADE)"; - - KeychainDatabase(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - - // make sure this is only done once, on the first instance! - boolean iAmIt = false; - synchronized(apgHack) { - if(!apgHack) { - iAmIt = true; - apgHack = true; - } - } - // if it's us, do the import - if(iAmIt) - checkAndImportApg(context); - } - - @Override - public void onCreate(SQLiteDatabase db) { - Log.w(Constants.TAG, "Creating database..."); - - db.execSQL(CREATE_KEYRINGS_PUBLIC); - db.execSQL(CREATE_KEYRINGS_SECRET); - db.execSQL(CREATE_KEYS); - db.execSQL(CREATE_USER_IDS); - db.execSQL(CREATE_CERTS); - db.execSQL(CREATE_API_APPS); - db.execSQL(CREATE_API_APPS_ACCOUNTS); - } - - @Override - public void onOpen(SQLiteDatabase db) { - super.onOpen(db); - if (!db.isReadOnly()) { - // Enable foreign key constraints - db.execSQL("PRAGMA foreign_keys=ON;"); - // TODO remove, once we remove the "always migrate" debug stuff - // db.execSQL("DROP TABLE certs;"); - // db.execSQL("DROP TABLE user_ids;"); - db.execSQL(CREATE_USER_IDS); - db.execSQL(CREATE_CERTS); - } - } - - @Override - public void onUpgrade(SQLiteDatabase db, int old, int nu) { - // don't care (this is version 1) - } - - /** This method tries to import data from a provided database. - * - * The sole assumptions made on this db are that there is a key_rings table - * with a key_ring_data, a master_key_id and a type column, the latter of - * which should be 1 for secret keys and 0 for public keys. - */ - public void checkAndImportApg(Context context) { - - boolean hasApgDb = false; { - // It's the Java way =( - String[] dbs = context.databaseList(); - for(String db : dbs) { - if(db.equals("apg.db")) { - hasApgDb = true; - break; - } - } - } - - if(!hasApgDb) - return; - - Log.d(Constants.TAG, "apg.db exists! Importing..."); - - SQLiteDatabase db = new SQLiteOpenHelper(context, "apg.db", null, 1) { - @Override - public void onCreate(SQLiteDatabase db) { - // should never happen - assert false; - } - @Override - public void onDowngrade(SQLiteDatabase db, int old, int nu) { - // don't care - } - @Override - public void onUpgrade(SQLiteDatabase db, int old, int nu) { - // don't care either - } - }.getReadableDatabase(); - - // kill current! - { // TODO don't kill current. - Log.d(Constants.TAG, "Truncating db..."); - SQLiteDatabase d = getWritableDatabase(); - d.execSQL("DELETE FROM keyrings_public"); - d.close(); - Log.d(Constants.TAG, "Ok."); - } - - Cursor c = null; - try { - // we insert in two steps: first, all public keys that have secret keys - c = db.rawQuery("SELECT key_ring_data FROM key_rings WHERE type = 1 OR EXISTS (" - + " SELECT 1 FROM key_rings d2 WHERE key_rings.master_key_id = d2.master_key_id" - + " AND d2.type = 1) ORDER BY type ASC", null); - Log.d(Constants.TAG, "Importing " + c.getCount() + " secret keyrings from apg.db..."); - for(int i = 0; i < c.getCount(); i++) { - c.moveToPosition(i); - byte[] data = c.getBlob(0); - PGPKeyRing ring = PgpConversionHelper.BytesToPGPKeyRing(data); - if(ring instanceof PGPPublicKeyRing) - ProviderHelper.saveKeyRing(context, (PGPPublicKeyRing) ring); - else if(ring instanceof PGPSecretKeyRing) - ProviderHelper.saveKeyRing(context, (PGPSecretKeyRing) ring); - else { - Log.e(Constants.TAG, "Unknown blob data type!"); - } - } - - // afterwards, insert all keys, starting with public keys that have secret keys, then - // secret keys, then all others. this order is necessary to ensure all certifications - // are recognized properly. - c = db.rawQuery("SELECT key_ring_data FROM key_rings ORDER BY (type = 0 AND EXISTS (" - + " SELECT 1 FROM key_rings d2 WHERE key_rings.master_key_id = d2.master_key_id AND" - + " d2.type = 1)) DESC, type DESC", null); - // import from old database - Log.d(Constants.TAG, "Importing " + c.getCount() + " keyrings from apg.db..."); - for(int i = 0; i < c.getCount(); i++) { - c.moveToPosition(i); - byte[] data = c.getBlob(0); - PGPKeyRing ring = PgpConversionHelper.BytesToPGPKeyRing(data); - if(ring instanceof PGPPublicKeyRing) - ProviderHelper.saveKeyRing(context, (PGPPublicKeyRing) ring); - else if(ring instanceof PGPSecretKeyRing) - ProviderHelper.saveKeyRing(context, (PGPSecretKeyRing) ring); - else { - Log.e(Constants.TAG, "Unknown blob data type!"); - } - } - - } catch(IOException e) { - Log.e(Constants.TAG, "Error importing apg db!", e); - return; - } finally { - if(c != null) - c.close(); - if(db != null) - db.close(); - } - - // TODO delete old db, if we are sure this works - // context.deleteDatabase("apg.db"); - Log.d(Constants.TAG, "All done, (not) deleting apg.db"); - - - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java deleted file mode 100644 index 9b9e4991d..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ /dev/null @@ -1,752 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.provider; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.content.UriMatcher; -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.database.sqlite.SQLiteConstraintException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteQueryBuilder; -import android.net.Uri; -import android.text.TextUtils; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.Arrays; -import java.util.HashMap; - -public class KeychainProvider extends ContentProvider { - - private static final int KEY_RINGS_UNIFIED = 101; - private static final int KEY_RINGS_PUBLIC = 102; - private static final int KEY_RINGS_SECRET = 103; - - private static final int KEY_RING_UNIFIED = 200; - private static final int KEY_RING_KEYS = 201; - private static final int KEY_RING_USER_IDS = 202; - private static final int KEY_RING_PUBLIC = 203; - private static final int KEY_RING_SECRET = 204; - private static final int KEY_RING_CERTS = 205; - private static final int KEY_RING_CERTS_SPECIFIC = 206; - - private static final int API_APPS = 301; - private static final int API_APPS_BY_PACKAGE_NAME = 303; - private static final int API_ACCOUNTS = 304; - private static final int API_ACCOUNTS_BY_ACCOUNT_NAME = 306; - - private static final int KEY_RINGS_FIND_BY_EMAIL = 400; - private static final int KEY_RINGS_FIND_BY_SUBKEY = 401; - - // private static final int DATA_STREAM = 501; - - protected UriMatcher mUriMatcher; - - /** - * Build and return a {@link UriMatcher} that catches all {@link Uri} variations supported by - * this {@link ContentProvider}. - */ - protected UriMatcher buildUriMatcher() { - final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); - - String authority = KeychainContract.CONTENT_AUTHORITY; - - /** - * list key_rings - * - * <pre> - * key_rings/unified - * key_rings/public - * </pre> - */ - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS - + "/" + KeychainContract.PATH_UNIFIED, - KEY_RINGS_UNIFIED); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS - + "/" + KeychainContract.PATH_PUBLIC, - KEY_RINGS_PUBLIC); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS - + "/" + KeychainContract.PATH_SECRET, - KEY_RINGS_SECRET); - - /** - * find by criteria other than master key id - * - * key_rings/find/email/_ - * key_rings/find/subkey/_ - * - */ - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" - + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_EMAIL + "/*", - KEY_RINGS_FIND_BY_EMAIL); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" - + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_SUBKEY + "/*", - KEY_RINGS_FIND_BY_SUBKEY); - - /** - * list key_ring specifics - * - * <pre> - * key_rings/_/unified - * key_rings/_/keys - * key_rings/_/user_ids - * key_rings/_/public - * key_rings/_/secret - * key_rings/_/certs - * key_rings/_/certs/_/_ - * </pre> - */ - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" - + KeychainContract.PATH_UNIFIED, - KEY_RING_UNIFIED); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" - + KeychainContract.PATH_KEYS, - KEY_RING_KEYS); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" - + KeychainContract.PATH_USER_IDS, - KEY_RING_USER_IDS); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" - + KeychainContract.PATH_PUBLIC, - KEY_RING_PUBLIC); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" - + KeychainContract.PATH_SECRET, - KEY_RING_SECRET); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" - + KeychainContract.PATH_CERTS, - KEY_RING_CERTS); - matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/" - + KeychainContract.PATH_CERTS + "/*/*", - KEY_RING_CERTS_SPECIFIC); - - /** - * API apps - * - * <pre> - * api_apps - * api_apps/_ (package name) - * - * api_apps/_/accounts - * api_apps/_/accounts/_ (account name) - * </pre> - */ - matcher.addURI(authority, KeychainContract.BASE_API_APPS, API_APPS); - matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*", API_APPS_BY_PACKAGE_NAME); - - matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/" - + KeychainContract.PATH_ACCOUNTS, API_ACCOUNTS); - matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/" - + KeychainContract.PATH_ACCOUNTS + "/*", API_ACCOUNTS_BY_ACCOUNT_NAME); - - /** - * data stream - * - * <pre> - * data / _ - * </pre> - */ - // matcher.addURI(authority, KeychainContract.BASE_DATA + "/*", DATA_STREAM); - - return matcher; - } - - private KeychainDatabase mKeychainDatabase; - - /** - * {@inheritDoc} - */ - @Override - public boolean onCreate() { - mUriMatcher = buildUriMatcher(); - return true; - } - - public KeychainDatabase getDb() { - if(mKeychainDatabase == null) - mKeychainDatabase = new KeychainDatabase(getContext()); - return mKeychainDatabase; - } - - /** - * {@inheritDoc} - */ - @Override - public String getType(Uri uri) { - final int match = mUriMatcher.match(uri); - switch (match) { - case KEY_RING_PUBLIC: - return KeyRings.CONTENT_ITEM_TYPE; - - case KEY_RING_KEYS: - return Keys.CONTENT_TYPE; - - case KEY_RING_USER_IDS: - return UserIds.CONTENT_TYPE; - - case KEY_RING_SECRET: - return KeyRings.CONTENT_ITEM_TYPE; - - case API_APPS: - return ApiApps.CONTENT_TYPE; - - case API_APPS_BY_PACKAGE_NAME: - return ApiApps.CONTENT_ITEM_TYPE; - - case API_ACCOUNTS: - return ApiAccounts.CONTENT_TYPE; - - case API_ACCOUNTS_BY_ACCOUNT_NAME: - return ApiAccounts.CONTENT_ITEM_TYPE; - - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - Log.v(Constants.TAG, "query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")"); - - SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); - - int match = mUriMatcher.match(uri); - - // all query() parameters, for good measure - String groupBy = null, having = null; - - switch (match) { - case KEY_RING_UNIFIED: - case KEY_RINGS_UNIFIED: - case KEY_RINGS_FIND_BY_EMAIL: - case KEY_RINGS_FIND_BY_SUBKEY: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); - projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id"); - projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID); - projectionMap.put(KeyRings.KEY_ID, Keys.KEY_ID); - projectionMap.put(KeyRings.KEY_SIZE, Keys.KEY_SIZE); - projectionMap.put(KeyRings.IS_REVOKED, Tables.KEYS + "." + Keys.IS_REVOKED); - projectionMap.put(KeyRings.CAN_CERTIFY, Keys.CAN_CERTIFY); - projectionMap.put(KeyRings.CAN_ENCRYPT, Keys.CAN_ENCRYPT); - projectionMap.put(KeyRings.CAN_SIGN, Keys.CAN_SIGN); - projectionMap.put(KeyRings.CREATION, Tables.KEYS + "." + Keys.CREATION); - projectionMap.put(KeyRings.EXPIRY, Keys.EXPIRY); - projectionMap.put(KeyRings.ALGORITHM, Keys.ALGORITHM); - projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT); - projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID); - projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED); - projectionMap.put(KeyRings.HAS_SECRET, "(" + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NOT NULL) AS " + KeyRings.HAS_SECRET); - qb.setProjectionMap(projectionMap); - - qb.setTables( - Tables.KEYS - + " INNER JOIN " + Tables.USER_IDS + " ON (" - + Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " = " - + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID - + " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = 0" - + ") LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON (" - + Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " = " - + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID - + ") LEFT JOIN " + Tables.CERTS + " ON (" - + Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " = " - + Tables.CERTS + "." + KeyRings.MASTER_KEY_ID - + " AND " + Tables.CERTS + "." + Certs.VERIFIED - + " = " + Certs.VERIFIED_SECRET - + ")" - ); - qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0"); - // in case there are multiple verifying certificates - groupBy = Tables.KEYS + "." + Keys.MASTER_KEY_ID; - - switch(match) { - case KEY_RING_UNIFIED: { - qb.appendWhere(" AND " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - break; - } - case KEY_RINGS_FIND_BY_SUBKEY: { - try { - String subkey = Long.valueOf(uri.getLastPathSegment()).toString(); - qb.appendWhere(" AND EXISTS (" - + " SELECT 1 FROM " + Tables.KEYS + " AS tmp" - + " WHERE tmp." + UserIds.MASTER_KEY_ID - + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " AND tmp." + Keys.KEY_ID + " = " + subkey + "" - + ")"); - } catch(NumberFormatException e) { - Log.e(Constants.TAG, "Malformed find by subkey query!", e); - qb.appendWhere(" AND 0"); - } - break; - } - case KEY_RINGS_FIND_BY_EMAIL: { - String chunks[] = uri.getLastPathSegment().split(" *, *"); - boolean gotCondition = false; - String emailWhere = ""; - // JAVA ♥ - for (int i = 0; i < chunks.length; ++i) { - if (chunks[i].length() == 0) { - continue; - } - if (i != 0) { - emailWhere += " OR "; - } - emailWhere += "tmp." + UserIds.USER_ID + " LIKE "; - // match '*<email>', so it has to be at the *end* of the user id - emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">"); - gotCondition = true; - } - if(gotCondition) { - qb.appendWhere(" AND EXISTS (" - + " SELECT 1 FROM " + Tables.USER_IDS + " AS tmp" - + " WHERE tmp." + UserIds.MASTER_KEY_ID - + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " AND (" + emailWhere + ")" - + ")"); - } else { - // TODO better way to do this? - Log.e(Constants.TAG, "Malformed find by email query!"); - qb.appendWhere(" AND 0"); - } - break; - } - } - - if (TextUtils.isEmpty(sortOrder)) { - sortOrder = - Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL ASC, " - + Tables.USER_IDS + "." + UserIds.USER_ID + " ASC"; - } - - // uri to watch is all /key_rings/ - uri = KeyRings.CONTENT_URI; - - break; - } - - case KEY_RING_KEYS: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); - projectionMap.put(Keys._ID, Tables.KEYS + ".oid AS _id"); - projectionMap.put(Keys.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID); - projectionMap.put(Keys.RANK, Tables.KEYS + "." + Keys.RANK); - projectionMap.put(Keys.KEY_ID, Keys.KEY_ID); - projectionMap.put(Keys.KEY_SIZE, Keys.KEY_SIZE); - projectionMap.put(Keys.IS_REVOKED, Keys.IS_REVOKED); - projectionMap.put(Keys.CAN_CERTIFY, Keys.CAN_CERTIFY); - projectionMap.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT); - projectionMap.put(Keys.CAN_SIGN, Keys.CAN_SIGN); - projectionMap.put(Keys.CREATION, Keys.CREATION); - projectionMap.put(Keys.EXPIRY, Keys.EXPIRY); - projectionMap.put(Keys.ALGORITHM, Keys.ALGORITHM); - projectionMap.put(Keys.FINGERPRINT, Keys.FINGERPRINT); - qb.setProjectionMap(projectionMap); - - qb.setTables(Tables.KEYS); - qb.appendWhere(Keys.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - - break; - } - - case KEY_RING_USER_IDS: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); - projectionMap.put(UserIds._ID, Tables.USER_IDS + ".oid AS _id"); - projectionMap.put(UserIds.MASTER_KEY_ID, Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID); - projectionMap.put(UserIds.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID); - projectionMap.put(UserIds.RANK, Tables.USER_IDS + "." + UserIds.RANK); - projectionMap.put(UserIds.IS_PRIMARY, Tables.USER_IDS + "." + UserIds.IS_PRIMARY); - projectionMap.put(UserIds.IS_REVOKED, Tables.USER_IDS + "." + UserIds.IS_REVOKED); - // we take the minimum (>0) here, where "1" is "verified by known secret key" - projectionMap.put(UserIds.VERIFIED, "MIN(" + Certs.VERIFIED + ") AS " + UserIds.VERIFIED); - qb.setProjectionMap(projectionMap); - - qb.setTables(Tables.USER_IDS - + " LEFT JOIN " + Tables.CERTS + " ON (" - + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " = " - + Tables.CERTS + "." + Certs.MASTER_KEY_ID - + " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = " - + Tables.CERTS + "." + Certs.RANK - + " AND " + Tables.CERTS + "." + Certs.VERIFIED + " > 0" - + ")"); - groupBy = Tables.USER_IDS + "." + UserIds.RANK; - - qb.appendWhere(Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - - if (TextUtils.isEmpty(sortOrder)) { - sortOrder = Tables.USER_IDS + "." + UserIds.RANK + " ASC"; - } - - break; - - } - - case KEY_RINGS_PUBLIC: - case KEY_RING_PUBLIC: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); - projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_PUBLIC + ".oid AS _id"); - projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID); - projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA); - qb.setProjectionMap(projectionMap); - - qb.setTables(Tables.KEY_RINGS_PUBLIC); - - if(match == KEY_RING_PUBLIC) { - qb.appendWhere(KeyRings.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - } - - break; - } - - case KEY_RINGS_SECRET: - case KEY_RING_SECRET: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); - projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_SECRET + ".oid AS _id"); - projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID); - projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA); - qb.setProjectionMap(projectionMap); - - qb.setTables(Tables.KEY_RINGS_SECRET); - - if(match == KEY_RING_SECRET) { - qb.appendWhere(KeyRings.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - } - - break; - } - - case KEY_RING_CERTS: - case KEY_RING_CERTS_SPECIFIC: { - HashMap<String, String> projectionMap = new HashMap<String, String>(); - projectionMap.put(Certs._ID, Tables.CERTS + ".oid AS " + Certs._ID); - projectionMap.put(Certs.MASTER_KEY_ID, Tables.CERTS + "." + Certs.MASTER_KEY_ID); - projectionMap.put(Certs.RANK, Tables.CERTS + "." + Certs.RANK); - projectionMap.put(Certs.VERIFIED, Tables.CERTS + "." + Certs.VERIFIED); - projectionMap.put(Certs.TYPE, Tables.CERTS + "." + Certs.TYPE); - projectionMap.put(Certs.CREATION, Tables.CERTS + "." + Certs.CREATION); - projectionMap.put(Certs.KEY_ID_CERTIFIER, Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER); - projectionMap.put(Certs.DATA, Tables.CERTS + "." + Certs.DATA); - projectionMap.put(Certs.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID); - projectionMap.put(Certs.SIGNER_UID, "signer." + UserIds.USER_ID + " AS " + Certs.SIGNER_UID); - qb.setProjectionMap(projectionMap); - - qb.setTables(Tables.CERTS - + " JOIN " + Tables.USER_IDS + " ON (" - + Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = " - + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID - + " AND " - + Tables.CERTS + "." + Certs.RANK + " = " - + Tables.USER_IDS + "." + UserIds.RANK - + ") LEFT JOIN " + Tables.USER_IDS + " AS signer ON (" - + Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER + " = " - + "signer." + UserIds.MASTER_KEY_ID - + " AND " - + "signer." + Keys.RANK + " = 0" - + ")"); - - groupBy = Tables.CERTS + "." + Certs.RANK + ", " - + Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER; - - qb.appendWhere(Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - if(match == KEY_RING_CERTS_SPECIFIC) { - qb.appendWhere(" AND " + Tables.CERTS + "." + Certs.RANK + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(3)); - qb.appendWhere(" AND " + Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER+ " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(4)); - } - - break; - } - - case API_APPS: - qb.setTables(Tables.API_APPS); - - break; - case API_APPS_BY_PACKAGE_NAME: - qb.setTables(Tables.API_APPS); - qb.appendWhere(ApiApps.PACKAGE_NAME + " = "); - qb.appendWhereEscapeString(uri.getLastPathSegment()); - - break; - case API_ACCOUNTS: - qb.setTables(Tables.API_ACCOUNTS); - qb.appendWhere(Tables.API_ACCOUNTS + "." + ApiAccounts.PACKAGE_NAME + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - - break; - case API_ACCOUNTS_BY_ACCOUNT_NAME: - qb.setTables(Tables.API_ACCOUNTS); - qb.appendWhere(Tables.API_ACCOUNTS + "." + ApiAccounts.PACKAGE_NAME + " = "); - qb.appendWhereEscapeString(uri.getPathSegments().get(1)); - - qb.appendWhere(" AND " + Tables.API_ACCOUNTS + "." + ApiAccounts.ACCOUNT_NAME + " = "); - qb.appendWhereEscapeString(uri.getLastPathSegment()); - - break; - default: - throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")"); - - } - - // If no sort order is specified use the default - String orderBy; - if (TextUtils.isEmpty(sortOrder)) { - orderBy = null; - } else { - orderBy = sortOrder; - } - - SQLiteDatabase db = getDb().getReadableDatabase(); - Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, having, orderBy); - - // Tell the cursor what uri to watch, so it knows when its source data changes - c.setNotificationUri(getContext().getContentResolver(), uri); - - if (Constants.DEBUG) { - Log.d(Constants.TAG, - "Query: " - + qb.buildQuery(projection, selection, selectionArgs, null, null, - orderBy, null)); - Log.d(Constants.TAG, "Cursor: " + DatabaseUtils.dumpCursorToString(c)); - } - - return c; - } - - /** - * {@inheritDoc} - */ - @Override - public Uri insert(Uri uri, ContentValues values) { - Log.d(Constants.TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")"); - - final SQLiteDatabase db = getDb().getWritableDatabase(); - - Uri rowUri = null; - Long keyId = null; - try { - final int match = mUriMatcher.match(uri); - - switch (match) { - case KEY_RING_PUBLIC: - db.insertOrThrow(Tables.KEY_RINGS_PUBLIC, null, values); - keyId = values.getAsLong(KeyRings.MASTER_KEY_ID); - break; - - case KEY_RING_SECRET: - db.insertOrThrow(Tables.KEY_RINGS_SECRET, null, values); - keyId = values.getAsLong(KeyRings.MASTER_KEY_ID); - break; - - case KEY_RING_KEYS: - Log.d(Constants.TAG, "keys"); - db.insertOrThrow(Tables.KEYS, null, values); - keyId = values.getAsLong(Keys.MASTER_KEY_ID); - break; - - case KEY_RING_USER_IDS: - db.insertOrThrow(Tables.USER_IDS, null, values); - keyId = values.getAsLong(UserIds.MASTER_KEY_ID); - break; - - case KEY_RING_CERTS: - // we replace here, keeping only the latest signature - // TODO this would be better handled in saveKeyRing directly! - db.replaceOrThrow(Tables.CERTS, null, values); - keyId = values.getAsLong(Certs.MASTER_KEY_ID); - break; - - case API_APPS: - db.insertOrThrow(Tables.API_APPS, null, values); - break; - - case API_ACCOUNTS: - // set foreign key automatically based on given uri - // e.g., api_apps/com.example.app/accounts/ - String packageName = uri.getPathSegments().get(1); - values.put(ApiAccounts.PACKAGE_NAME, packageName); - - Log.d(Constants.TAG, "provider packageName: " + packageName); - - db.insertOrThrow(Tables.API_ACCOUNTS, null, values); - // TODO: this is wrong: -// rowUri = ApiAccounts.buildIdUri(Long.toString(rowId)); - - break; - - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); - } - - if(keyId != null) { - uri = KeyRings.buildGenericKeyRingUri(keyId.toString()); - rowUri = uri; - } - - // notify of changes in db - getContext().getContentResolver().notifyChange(uri, null); - - } catch (SQLiteConstraintException e) { - Log.e(Constants.TAG, "Constraint exception on insert! Entry already existing?", e); - } - - return rowUri; - } - - /** - * {@inheritDoc} - */ - @Override - public int delete(Uri uri, String additionalSelection, String[] selectionArgs) { - Log.v(Constants.TAG, "delete(uri=" + uri + ")"); - - final SQLiteDatabase db = getDb().getWritableDatabase(); - - int count; - final int match = mUriMatcher.match(uri); - - switch (match) { - case KEY_RING_PUBLIC: { - @SuppressWarnings("ConstantConditions") // ensured by uriMatcher above - String selection = KeyRings.MASTER_KEY_ID + " = " + uri.getPathSegments().get(1); - if (!TextUtils.isEmpty(additionalSelection)) { - selection += " AND (" + additionalSelection + ")"; - } - // corresponding keys and userIds are deleted by ON DELETE CASCADE - count = db.delete(Tables.KEY_RINGS_PUBLIC, selection, selectionArgs); - uri = KeyRings.buildGenericKeyRingUri(uri.getPathSegments().get(1)); - break; - } - case KEY_RING_SECRET: { - @SuppressWarnings("ConstantConditions") // ensured by uriMatcher above - String selection = KeyRings.MASTER_KEY_ID + " = " + uri.getPathSegments().get(1); - if (!TextUtils.isEmpty(additionalSelection)) { - selection += " AND (" + additionalSelection + ")"; - } - count = db.delete(Tables.KEY_RINGS_SECRET, selection, selectionArgs); - uri = KeyRings.buildGenericKeyRingUri(uri.getPathSegments().get(1)); - break; - } - - case API_APPS_BY_PACKAGE_NAME: - count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, additionalSelection), - selectionArgs); - break; - case API_ACCOUNTS_BY_ACCOUNT_NAME: - count = db.delete(Tables.API_ACCOUNTS, buildDefaultApiAccountsSelection(uri, additionalSelection), - selectionArgs); - break; - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); - } - - // notify of changes in db - getContext().getContentResolver().notifyChange(uri, null); - - return count; - } - - /** - * {@inheritDoc} - */ - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - Log.v(Constants.TAG, "update(uri=" + uri + ", values=" + values.toString() + ")"); - - final SQLiteDatabase db = mKeychainDatabase.getWritableDatabase(); - - String defaultSelection = null; - int count = 0; - try { - final int match = mUriMatcher.match(uri); - switch (match) { - case API_APPS_BY_PACKAGE_NAME: - count = db.update(Tables.API_APPS, values, - buildDefaultApiAppsSelection(uri, selection), selectionArgs); - break; - case API_ACCOUNTS_BY_ACCOUNT_NAME: - count = db.update(Tables.API_ACCOUNTS, values, - buildDefaultApiAccountsSelection(uri, selection), selectionArgs); - break; - default: - throw new UnsupportedOperationException("Unknown uri: " + uri); - } - - // notify of changes in db - getContext().getContentResolver().notifyChange(uri, null); - - } catch (SQLiteConstraintException e) { - Log.e(Constants.TAG, "Constraint exception on update! Entry already existing?"); - } - - return count; - } - - /** - * Build default selection statement for API apps. If no extra selection is specified only build - * where clause with rowId - * - * @param uri - * @param selection - * @return - */ - private String buildDefaultApiAppsSelection(Uri uri, String selection) { - String packageName = DatabaseUtils.sqlEscapeString(uri.getLastPathSegment()); - - String andSelection = ""; - if (!TextUtils.isEmpty(selection)) { - andSelection = " AND (" + selection + ")"; - } - - return ApiApps.PACKAGE_NAME + "=" + packageName + andSelection; - } - - private String buildDefaultApiAccountsSelection(Uri uri, String selection) { - String packageName = DatabaseUtils.sqlEscapeString(uri.getPathSegments().get(1)); - String accountName = DatabaseUtils.sqlEscapeString(uri.getLastPathSegment()); - - String andSelection = ""; - if (!TextUtils.isEmpty(selection)) { - andSelection = " AND (" + selection + ")"; - } - - return ApiAccounts.PACKAGE_NAME + "=" + packageName + " AND " - + ApiAccounts.ACCOUNT_NAME + "=" + accountName - + andSelection; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java deleted file mode 100644 index 701ffc6af..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobContract.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.provider; - -import android.net.Uri; -import android.provider.BaseColumns; -import org.sufficientlysecure.keychain.Constants; - -public class KeychainServiceBlobContract { - - interface BlobsColumns { - String KEY = "key"; - } - - public static final String CONTENT_AUTHORITY = Constants.PACKAGE_NAME + ".blobs"; - - private static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY); - - public static class Blobs implements BlobsColumns, BaseColumns { - public static final Uri CONTENT_URI = BASE_CONTENT_URI; - } - - private KeychainServiceBlobContract() { - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java deleted file mode 100644 index bc7de0b37..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobDatabase.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2011 Markus Doits <markus.doits@googlemail.com> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.provider; - -import android.content.Context; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.provider.BaseColumns; -import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.BlobsColumns; - -public class KeychainServiceBlobDatabase extends SQLiteOpenHelper { - private static final String DATABASE_NAME = "openkeychain_blob.db"; - private static final int DATABASE_VERSION = 2; - - public static final String TABLE = "data"; - - public KeychainServiceBlobDatabase(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + TABLE + " ( " + BaseColumns._ID - + " INTEGER PRIMARY KEY AUTOINCREMENT, " + BlobsColumns.KEY + " TEXT NOT NULL)"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - // no upgrade necessary yet - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java deleted file mode 100644 index aa30e845d..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainServiceBlobProvider.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2011 Markus Doits <markus.doits@googlemail.com> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.provider; - -import android.content.ContentProvider; -import android.content.ContentUris; -import android.content.ContentValues; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import android.provider.BaseColumns; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.Blobs; -import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.BlobsColumns; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.List; -import java.util.UUID; - -public class KeychainServiceBlobProvider extends ContentProvider { - private static final String STORE_PATH = Constants.Path.APP_DIR + "/KeychainBlobs"; - - private KeychainServiceBlobDatabase mBlobDatabase = null; - - public KeychainServiceBlobProvider() { - File dir = new File(STORE_PATH); - dir.mkdirs(); - } - - @Override - public boolean onCreate() { - mBlobDatabase = new KeychainServiceBlobDatabase(getContext()); - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public Uri insert(Uri uri, ContentValues ignored) { - // ContentValues are actually ignored, because we want to store a blob with no more - // information but have to create an record with the password generated here first - ContentValues vals = new ContentValues(); - - // Insert a random key in the database. This has to provided by the caller when updating or - // getting the blob - String password = UUID.randomUUID().toString(); - vals.put(BlobsColumns.KEY, password); - - SQLiteDatabase db = mBlobDatabase.getWritableDatabase(); - long newRowId = db.insert(KeychainServiceBlobDatabase.TABLE, null, vals); - Uri insertedUri = ContentUris.withAppendedId(Blobs.CONTENT_URI, newRowId); - - return Uri.withAppendedPath(insertedUri, password); - } - - /** - * {@inheritDoc} - */ - @Override - public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException, - FileNotFoundException { - Log.d(Constants.TAG, "openFile() called with uri: " + uri.toString() + " and mode: " + mode); - - List<String> segments = uri.getPathSegments(); - if (segments.size() < 2) { - throw new SecurityException("Password not found in URI"); - } - String id = segments.get(0); - String key = segments.get(1); - - Log.d(Constants.TAG, "Got id: " + id + " and key: " + key); - - // get the data - SQLiteDatabase db = mBlobDatabase.getReadableDatabase(); - Cursor result = db.query(KeychainServiceBlobDatabase.TABLE, new String[]{BaseColumns._ID}, - BaseColumns._ID + " = ? and " + BlobsColumns.KEY + " = ?", - new String[]{id, key}, null, null, null); - - if (result.getCount() == 0) { - // either the key is wrong or no id exists - throw new FileNotFoundException("No file found with that ID and/or password"); - } - - File targetFile = new File(STORE_PATH, id); - if (mode.equals("w")) { - Log.d(Constants.TAG, "Try to open file w"); - if (!targetFile.exists()) { - try { - targetFile.createNewFile(); - } catch (IOException e) { - Log.e(Constants.TAG, "Got IEOException on creating new file", e); - throw new FileNotFoundException("Could not create file to write to"); - } - } - return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_WRITE_ONLY - | ParcelFileDescriptor.MODE_TRUNCATE); - } else if (mode.equals("r")) { - Log.d(Constants.TAG, "Try to open file r"); - if (!targetFile.exists()) { - throw new FileNotFoundException("Error: Could not find the file requested"); - } - return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY); - } - - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public String getType(Uri uri) { - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - /** - * {@inheritDoc} - */ - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java deleted file mode 100644 index 5e6d37237..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ /dev/null @@ -1,673 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.provider; - -import android.content.ContentProviderOperation; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.OperationApplicationException; -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.net.Uri; -import android.os.RemoteException; - -import org.spongycastle.bcpg.ArmoredOutputStream; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; -import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; -import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.remote.AccountSettings; -import org.sufficientlysecure.keychain.remote.AppSettings; -import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.security.SignatureException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class ProviderHelper { - - // If we ever switch to api level 11, we can ditch this whole mess! - public static final int FIELD_TYPE_NULL = 1; - // this is called integer to stay coherent with the constants in Cursor (api level 11) - public static final int FIELD_TYPE_INTEGER = 2; - public static final int FIELD_TYPE_FLOAT = 3; - public static final int FIELD_TYPE_STRING = 4; - public static final int FIELD_TYPE_BLOB = 5; - - public static Object getGenericData(Context context, Uri uri, String column, int type) { - return getGenericData(context, uri, new String[] { column }, new int[] { type }).get(column); - } - - public static HashMap<String,Object> getGenericData(Context context, Uri uri, String[] proj, int[] types) { - Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null); - - HashMap<String, Object> result = new HashMap<String, Object>(proj.length); - if (cursor != null && cursor.moveToFirst()) { - int pos = 0; - for(String p : proj) { - switch(types[pos]) { - case FIELD_TYPE_NULL: result.put(p, cursor.isNull(pos)); break; - case FIELD_TYPE_INTEGER: result.put(p, cursor.getLong(pos)); break; - case FIELD_TYPE_FLOAT: result.put(p, cursor.getFloat(pos)); break; - case FIELD_TYPE_STRING: result.put(p, cursor.getString(pos)); break; - case FIELD_TYPE_BLOB: result.put(p, cursor.getBlob(pos)); break; - } - pos += 1; - } - } - - if (cursor != null) { - cursor.close(); - } - - return result; - } - - public static Object getUnifiedData(Context context, long masterKeyId, String column, int type) { - return getUnifiedData(context, masterKeyId, new String[] { column }, new int[] { type }).get(column); - } - - public static HashMap<String,Object> getUnifiedData(Context context, long masterKeyId, String[] proj, int[] types) { - return getGenericData(context, KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)), proj, types); - } - - /** - * Find the master key id related to a given query. The id will either be extracted from the - * query, which should work for all specific /key_rings/ queries, or will be queried if it can't. - */ - public static long getMasterKeyId(Context context, Uri queryUri) { - // try extracting from the uri first - String firstSegment = queryUri.getPathSegments().get(1); - if(!firstSegment.equals("find")) try { - return Long.parseLong(firstSegment); - } catch(NumberFormatException e) { - // didn't work? oh well. - Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying..."); - } - Object data = getGenericData(context, queryUri, KeyRings.MASTER_KEY_ID, FIELD_TYPE_INTEGER); - if(data != null) - return (Long) data; - // TODO better error handling? - return 0L; - } - - public static Map<Long, PGPKeyRing> getPGPKeyRings(Context context, Uri queryUri) { - Cursor cursor = context.getContentResolver().query(queryUri, - new String[]{KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA }, - null, null, null); - - Map<Long, PGPKeyRing> result = new HashMap<Long, PGPKeyRing>(cursor.getCount()); - if (cursor != null && cursor.moveToFirst()) do { - long masterKeyId = cursor.getLong(0); - byte[] data = cursor.getBlob(1); - if (data != null) { - result.put(masterKeyId, PgpConversionHelper.BytesToPGPKeyRing(data)); - } - } while(cursor.moveToNext()); - - if (cursor != null) { - cursor.close(); - } - - return result; - } - public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) { - Map<Long, PGPKeyRing> result = getPGPKeyRings(context, queryUri); - if(result.isEmpty()) - return null; - return result.values().iterator().next(); - } - - public static PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(Context context, long keyId) { - Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId)); - long masterKeyId = getMasterKeyId(context, uri); - if(masterKeyId != 0) - return getPGPPublicKeyRing(context, masterKeyId); - return null; - } - public static PGPSecretKeyRing getPGPSecretKeyRingWithKeyId(Context context, long keyId) { - Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId)); - long masterKeyId = getMasterKeyId(context, uri); - if(masterKeyId != 0) - return getPGPSecretKeyRing(context, masterKeyId); - return null; - } - - /** - * Retrieves the actual PGPPublicKeyRing object from the database blob based on the masterKeyId - */ - public static PGPPublicKeyRing getPGPPublicKeyRing(Context context, - long masterKeyId) { - Uri queryUri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)); - return (PGPPublicKeyRing) getPGPKeyRing(context, queryUri); - } - - /** - * Retrieves the actual PGPSecretKeyRing object from the database blob based on the maserKeyId - */ - public static PGPSecretKeyRing getPGPSecretKeyRing(Context context, - long masterKeyId) { - Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)); - return (PGPSecretKeyRing) getPGPKeyRing(context, queryUri); - } - - /** - * Saves PGPPublicKeyRing with its keys and userIds in DB - */ - @SuppressWarnings("unchecked") - public static void saveKeyRing(Context context, PGPPublicKeyRing keyRing) throws IOException { - PGPPublicKey masterKey = keyRing.getPublicKey(); - long masterKeyId = masterKey.getKeyID(); - - // IF there is a secret key, preserve it! - PGPSecretKeyRing secretRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId); - - // delete old version of this keyRing, which also deletes all keys and userIds on cascade - try { - context.getContentResolver().delete(KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null); - } catch (UnsupportedOperationException e) { - Log.e(Constants.TAG, "Key could not be deleted! Maybe we are creating a new one!", e); - } - - ContentValues values = new ContentValues(); - // use exactly the same _ID again to replace key in-place. - // NOTE: If we would not use the same _ID again, - // getting back to the ViewKeyActivity would result in Nullpointer, - // because the currently loaded key would be gone from the database - values.put(KeyRingData.MASTER_KEY_ID, masterKeyId); - values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded()); - - // insert new version of this keyRing - Uri uri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)); - Uri insertedUri = context.getContentResolver().insert(uri, values); - - // save all keys and userIds included in keyRing object in database - ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(); - - int rank = 0; - for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) { - operations.add(buildPublicKeyOperations(context, masterKeyId, key, rank)); - ++rank; - } - - // get a list of owned secret keys, for verification filtering - Map<Long, PGPKeyRing> allKeyRings = getPGPKeyRings(context, KeyRingData.buildSecretKeyRingUri()); - // special case: available secret keys verify themselves! - if(secretRing != null) - allKeyRings.put(secretRing.getSecretKey().getKeyID(), secretRing); - - // classify and order user ids. primary are moved to the front, revoked to the back, - // otherwise the order in the keyfile is preserved. - List<UserIdItem> uids = new ArrayList<UserIdItem>(); - - for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) { - UserIdItem item = new UserIdItem(); - uids.add(item); - item.userId = userId; - - // look through signatures for this specific key - for (PGPSignature cert : new IterableIterator<PGPSignature>( - masterKey.getSignaturesForID(userId))) { - long certId = cert.getKeyID(); - try { - // self signature - if(certId == masterKeyId) { - cert.init(new JcaPGPContentVerifierBuilderProvider().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME), masterKey); - if(!cert.verifyCertification(userId, masterKey)) { - // not verified?! dang! TODO notify user? this is kinda serious... - Log.e(Constants.TAG, "Could not verify self signature for " + userId + "!"); - continue; - } - // is this the first, or a more recent certificate? - if(item.selfCert == null || - item.selfCert.getCreationTime().before(cert.getCreationTime())) { - item.selfCert = cert; - item.isPrimary = cert.getHashedSubPackets().isPrimaryUserID(); - item.isRevoked = - cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION; - } - } - // verify signatures from known private keys - if(allKeyRings.containsKey(certId)) { - // mark them as verified - cert.init(new JcaPGPContentVerifierBuilderProvider().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME), - allKeyRings.get(certId).getPublicKey()); - if(cert.verifyCertification(userId, masterKey)) { - item.trustedCerts.add(cert); - } - } - } catch(SignatureException e) { - Log.e(Constants.TAG, "Signature verification failed! " - + PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID()) - + " from " - + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e); - } catch(PGPException e) { - Log.e(Constants.TAG, "Signature verification failed! " - + PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID()) - + " from " - + PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e); - } - } - } - - // primary before regular before revoked (see UserIdItem.compareTo) - // this is a stable sort, so the order of keys is otherwise preserved. - Collections.sort(uids); - // iterate and put into db - for(int userIdRank = 0; userIdRank < uids.size(); userIdRank++) { - UserIdItem item = uids.get(userIdRank); - operations.add(buildUserIdOperations(masterKeyId, item, userIdRank)); - // no self cert is bad, but allowed by the rfc... - if(item.selfCert != null) { - operations.add(buildCertOperations( - masterKeyId, userIdRank, item.selfCert, Certs.VERIFIED_SELF)); - } - // don't bother with trusted certs if the uid is revoked, anyways - if(item.isRevoked) { - continue; - } - for(int i = 0; i < item.trustedCerts.size(); i++) { - operations.add(buildCertOperations( - masterKeyId, userIdRank, item.trustedCerts.get(i), Certs.VERIFIED_SECRET)); - } - } - - try { - context.getContentResolver().applyBatch(KeychainContract.CONTENT_AUTHORITY, operations); - } catch (RemoteException e) { - Log.e(Constants.TAG, "applyBatch failed!", e); - } catch (OperationApplicationException e) { - Log.e(Constants.TAG, "applyBatch failed!", e); - } - - // Save the saved keyring (if any) - if(secretRing != null) { - saveKeyRing(context, secretRing); - } - - } - - private static class UserIdItem implements Comparable<UserIdItem> { - String userId; - boolean isPrimary = false; - boolean isRevoked = false; - PGPSignature selfCert; - List<PGPSignature> trustedCerts = new ArrayList<PGPSignature>(); - - @Override - public int compareTo(UserIdItem o) { - // if one key is primary but the other isn't, the primary one always comes first - if(isPrimary != o.isPrimary) - return isPrimary ? -1 : 1; - // revoked keys always come last! - if(isRevoked != o.isRevoked) - return isRevoked ? 1 : -1; - return 0; - } - } - - /** - * Saves a PGPSecretKeyRing in the DB. This will only work if a corresponding public keyring - * is already in the database! - */ - @SuppressWarnings("unchecked") - public static void saveKeyRing(Context context, PGPSecretKeyRing keyRing) throws IOException { - long masterKeyId = keyRing.getPublicKey().getKeyID(); - - // save secret keyring - ContentValues values = new ContentValues(); - values.put(KeyRingData.MASTER_KEY_ID, masterKeyId); - values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded()); - // insert new version of this keyRing - Uri uri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)); - context.getContentResolver().insert(uri, values); - - } - - /** - * Saves (or updates) a pair of public and secret KeyRings in the database - */ - @SuppressWarnings("unchecked") - public static void saveKeyRing(Context context, PGPPublicKeyRing pubRing, PGPSecretKeyRing privRing) throws IOException { - long masterKeyId = pubRing.getPublicKey().getKeyID(); - - // delete secret keyring (so it isn't unnecessarily saved by public-saveKeyRing below) - context.getContentResolver().delete(KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null); - - // save public keyring - saveKeyRing(context, pubRing); - saveKeyRing(context, privRing); - } - - /** - * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing - */ - private static ContentProviderOperation buildPublicKeyOperations(Context context, - long masterKeyId, PGPPublicKey key, int rank) throws IOException { - - ContentValues values = new ContentValues(); - values.put(Keys.MASTER_KEY_ID, masterKeyId); - values.put(Keys.RANK, rank); - - values.put(Keys.KEY_ID, key.getKeyID()); - values.put(Keys.KEY_SIZE, key.getBitStrength()); - values.put(Keys.ALGORITHM, key.getAlgorithm()); - values.put(Keys.FINGERPRINT, key.getFingerprint()); - - values.put(Keys.CAN_CERTIFY, (PgpKeyHelper.isCertificationKey(key))); - values.put(Keys.CAN_SIGN, (PgpKeyHelper.isSigningKey(key))); - values.put(Keys.CAN_ENCRYPT, PgpKeyHelper.isEncryptionKey(key)); - values.put(Keys.IS_REVOKED, key.isRevoked()); - - values.put(Keys.CREATION, PgpKeyHelper.getCreationDate(key).getTime() / 1000); - Date expiryDate = PgpKeyHelper.getExpiryDate(key); - if (expiryDate != null) { - values.put(Keys.EXPIRY, expiryDate.getTime() / 1000); - } - - Uri uri = Keys.buildKeysUri(Long.toString(masterKeyId)); - - return ContentProviderOperation.newInsert(uri).withValues(values).build(); - } - - /** - * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing - */ - private static ContentProviderOperation buildCertOperations(long masterKeyId, - int rank, - PGPSignature cert, - int verified) - throws IOException { - ContentValues values = new ContentValues(); - values.put(Certs.MASTER_KEY_ID, masterKeyId); - values.put(Certs.RANK, rank); - values.put(Certs.KEY_ID_CERTIFIER, cert.getKeyID()); - values.put(Certs.TYPE, cert.getSignatureType()); - values.put(Certs.CREATION, cert.getCreationTime().getTime() / 1000); - values.put(Certs.VERIFIED, verified); - values.put(Certs.DATA, cert.getEncoded()); - - Uri uri = Certs.buildCertsUri(Long.toString(masterKeyId)); - - return ContentProviderOperation.newInsert(uri).withValues(values).build(); - } - - /** - * Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing - */ - private static ContentProviderOperation buildUserIdOperations(long masterKeyId, UserIdItem item, - int rank) { - ContentValues values = new ContentValues(); - values.put(UserIds.MASTER_KEY_ID, masterKeyId); - values.put(UserIds.USER_ID, item.userId); - values.put(UserIds.IS_PRIMARY, item.isPrimary); - values.put(UserIds.IS_REVOKED, item.isRevoked); - values.put(UserIds.RANK, rank); - - Uri uri = UserIds.buildUserIdsUri(Long.toString(masterKeyId)); - - return ContentProviderOperation.newInsert(uri).withValues(values).build(); - } - - public static ArrayList<String> getKeyRingsAsArmoredString(Context context, long[] masterKeyIds) { - ArrayList<String> output = new ArrayList<String>(); - - if (masterKeyIds != null && masterKeyIds.length > 0) { - - Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, masterKeyIds); - - if (cursor != null) { - int masterIdCol = cursor.getColumnIndex(KeyRingData.MASTER_KEY_ID); - int dataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA); - if (cursor.moveToFirst()) { - do { - Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol)); - - // get actual keyring data blob and write it to ByteArrayOutputStream - try { - Object keyRing = null; - byte[] data = cursor.getBlob(dataCol); - if (data != null) { - keyRing = PgpConversionHelper.BytesToPGPKeyRing(data); - } - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ArmoredOutputStream aos = new ArmoredOutputStream(bos); - aos.setHeader("Version", PgpHelper.getFullVersion(context)); - - if (keyRing instanceof PGPSecretKeyRing) { - aos.write(((PGPSecretKeyRing) keyRing).getEncoded()); - } else if (keyRing instanceof PGPPublicKeyRing) { - aos.write(((PGPPublicKeyRing) keyRing).getEncoded()); - } - aos.close(); - - String armoredKey = bos.toString("UTF-8"); - - Log.d(Constants.TAG, "armoredKey:" + armoredKey); - - output.add(armoredKey); - } catch (IOException e) { - Log.e(Constants.TAG, "IOException", e); - } - } while (cursor.moveToNext()); - } - } - - if (cursor != null) { - cursor.close(); - } - - } else { - Log.e(Constants.TAG, "No master keys given!"); - } - - if (output.size() > 0) { - return output; - } else { - return null; - } - } - - private static Cursor getCursorWithSelectedKeyringMasterKeyIds(Context context, long[] masterKeyIds) { - Cursor cursor = null; - if (masterKeyIds != null && masterKeyIds.length > 0) { - - String inMasterKeyList = KeyRingData.MASTER_KEY_ID + " IN ("; - for (int i = 0; i < masterKeyIds.length; ++i) { - if (i != 0) { - inMasterKeyList += ", "; - } - inMasterKeyList += DatabaseUtils.sqlEscapeString("" + masterKeyIds[i]); - } - inMasterKeyList += ")"; - - cursor = context.getContentResolver().query(KeyRingData.buildPublicKeyRingUri(), new String[] { - KeyRingData._ID, KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA - }, inMasterKeyList, null, null); - } - - return cursor; - } - - public static ArrayList<String> getRegisteredApiApps(Context context) { - Cursor cursor = context.getContentResolver().query(ApiApps.CONTENT_URI, null, null, null, - null); - - ArrayList<String> packageNames = new ArrayList<String>(); - if (cursor != null) { - int packageNameCol = cursor.getColumnIndex(ApiApps.PACKAGE_NAME); - if (cursor.moveToFirst()) { - do { - packageNames.add(cursor.getString(packageNameCol)); - } while (cursor.moveToNext()); - } - } - - if (cursor != null) { - cursor.close(); - } - - return packageNames; - } - - private static ContentValues contentValueForApiApps(AppSettings appSettings) { - ContentValues values = new ContentValues(); - values.put(ApiApps.PACKAGE_NAME, appSettings.getPackageName()); - values.put(ApiApps.PACKAGE_SIGNATURE, appSettings.getPackageSignature()); - return values; - } - - private static ContentValues contentValueForApiAccounts(AccountSettings accSettings) { - ContentValues values = new ContentValues(); - values.put(KeychainContract.ApiAccounts.ACCOUNT_NAME, accSettings.getAccountName()); - values.put(KeychainContract.ApiAccounts.KEY_ID, accSettings.getKeyId()); - values.put(KeychainContract.ApiAccounts.COMPRESSION, accSettings.getCompression()); - values.put(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM, accSettings.getEncryptionAlgorithm()); - values.put(KeychainContract.ApiAccounts.HASH_ALORITHM, accSettings.getHashAlgorithm()); - return values; - } - - public static void insertApiApp(Context context, AppSettings appSettings) { - context.getContentResolver().insert(KeychainContract.ApiApps.CONTENT_URI, - contentValueForApiApps(appSettings)); - } - - public static void insertApiAccount(Context context, Uri uri, AccountSettings accSettings) { - context.getContentResolver().insert(uri, contentValueForApiAccounts(accSettings)); - } - - public static void updateApiApp(Context context, AppSettings appSettings, Uri uri) { - if (context.getContentResolver().update(uri, contentValueForApiApps(appSettings), null, - null) <= 0) { - throw new RuntimeException(); - } - } - - public static void updateApiAccount(Context context, AccountSettings accSettings, Uri uri) { - if (context.getContentResolver().update(uri, contentValueForApiAccounts(accSettings), null, - null) <= 0) { - throw new RuntimeException(); - } - } - - /** - * Must be an uri pointing to an account - * - * @param context - * @param uri - * @return - */ - public static AppSettings getApiAppSettings(Context context, Uri uri) { - AppSettings settings = null; - - Cursor cur = context.getContentResolver().query(uri, null, null, null, null); - if (cur != null && cur.moveToFirst()) { - settings = new AppSettings(); - settings.setPackageName(cur.getString( - cur.getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME))); - settings.setPackageSignature(cur.getBlob( - cur.getColumnIndex(KeychainContract.ApiApps.PACKAGE_SIGNATURE))); - } - - return settings; - } - - public static AccountSettings getApiAccountSettings(Context context, Uri accountUri) { - AccountSettings settings = null; - - Cursor cur = context.getContentResolver().query(accountUri, null, null, null, null); - if (cur != null && cur.moveToFirst()) { - settings = new AccountSettings(); - - settings.setAccountName(cur.getString( - cur.getColumnIndex(KeychainContract.ApiAccounts.ACCOUNT_NAME))); - settings.setKeyId(cur.getLong( - cur.getColumnIndex(KeychainContract.ApiAccounts.KEY_ID))); - settings.setCompression(cur.getInt( - cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.COMPRESSION))); - settings.setHashAlgorithm(cur.getInt( - cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.HASH_ALORITHM))); - settings.setEncryptionAlgorithm(cur.getInt( - cur.getColumnIndexOrThrow(KeychainContract.ApiAccounts.ENCRYPTION_ALGORITHM))); - } - - return settings; - } - - public static Set<Long> getAllKeyIdsForApp(Context context, Uri uri) { - Set<Long> keyIds = new HashSet<Long>(); - - Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); - if (cursor != null) { - int keyIdColumn = cursor.getColumnIndex(KeychainContract.ApiAccounts.KEY_ID); - while (cursor.moveToNext()) { - keyIds.add(cursor.getLong(keyIdColumn)); - } - } - - return keyIds; - } - - public static byte[] getApiAppSignature(Context context, String packageName) { - Uri queryUri = ApiApps.buildByPackageNameUri(packageName); - - String[] projection = new String[]{ApiApps.PACKAGE_SIGNATURE}; - - ContentResolver cr = context.getContentResolver(); - Cursor cursor = cr.query(queryUri, projection, null, null, null); - - byte[] signature = null; - if (cursor != null && cursor.moveToFirst()) { - int signatureCol = 0; - - signature = cursor.getBlob(signatureCol); - } - - if (cursor != null) { - cursor.close(); - } - - return signature; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AccountSettings.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AccountSettings.java deleted file mode 100644 index 832cbc752..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AccountSettings.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote; - -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.openpgp.PGPEncryptedData; -import org.sufficientlysecure.keychain.Id; - -public class AccountSettings { - private String mAccountName; - private long mKeyId = Id.key.none; - private int mEncryptionAlgorithm; - private int mHashAlgorithm; - private int mCompression; - - public AccountSettings() { - - } - - public AccountSettings(String accountName) { - super(); - this.mAccountName = accountName; - - // defaults: - this.mEncryptionAlgorithm = PGPEncryptedData.AES_256; - this.mHashAlgorithm = HashAlgorithmTags.SHA512; - this.mCompression = Id.choice.compression.zlib; - } - - public String getAccountName() { - return mAccountName; - } - - public void setAccountName(String mAccountName) { - this.mAccountName = mAccountName; - } - - public long getKeyId() { - return mKeyId; - } - - public void setKeyId(long scretKeyId) { - this.mKeyId = scretKeyId; - } - - public int getEncryptionAlgorithm() { - return mEncryptionAlgorithm; - } - - public void setEncryptionAlgorithm(int encryptionAlgorithm) { - this.mEncryptionAlgorithm = encryptionAlgorithm; - } - - public int getHashAlgorithm() { - return mHashAlgorithm; - } - - public void setHashAlgorithm(int hashAlgorithm) { - this.mHashAlgorithm = hashAlgorithm; - } - - public int getCompression() { - return mCompression; - } - - public void setCompression(int compression) { - this.mCompression = compression; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java deleted file mode 100644 index a3f9f84c9..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/AppSettings.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote; - -public class AppSettings { - private String mPackageName; - private byte[] mPackageSignature; - - public AppSettings() { - - } - - public AppSettings(String packageName, byte[] packageSignature) { - super(); - this.mPackageName = packageName; - this.mPackageSignature = packageSignature; - } - - public String getPackageName() { - return mPackageName; - } - - public void setPackageName(String packageName) { - this.mPackageName = packageName; - } - - public byte[] getPackageSignature() { - return mPackageSignature; - } - - public void setPackageSignature(byte[] packageSignature) { - this.mPackageSignature = packageSignature; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java deleted file mode 100644 index b38fea5a9..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote; - -import android.app.PendingIntent; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; - -import org.openintents.openpgp.IOpenPgpService; -import org.openintents.openpgp.OpenPgpError; -import org.openintents.openpgp.OpenPgpSignatureResult; -import org.openintents.openpgp.util.OpenPgpApi; -import org.spongycastle.util.Arrays; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; -import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.ui.ImportKeysActivity; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Set; - -public class OpenPgpService extends RemoteService { - - /** - * Search database for key ids based on emails. - * - * @param encryptionUserIds - * @return - */ - private Intent getKeyIdsFromEmails(Intent data, String[] encryptionUserIds) { - // find key ids to given emails in database - ArrayList<Long> keyIds = new ArrayList<Long>(); - - boolean missingUserIdsCheck = false; - boolean duplicateUserIdsCheck = false; - ArrayList<String> missingUserIds = new ArrayList<String>(); - ArrayList<String> duplicateUserIds = new ArrayList<String>(); - - for (String email : encryptionUserIds) { - Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email); - Cursor cur = getContentResolver().query(uri, null, null, null, null); - if (cur.moveToFirst()) { - long id = cur.getLong(cur.getColumnIndex(KeyRings.MASTER_KEY_ID)); - keyIds.add(id); - } else { - missingUserIdsCheck = true; - missingUserIds.add(email); - Log.d(Constants.TAG, "user id missing"); - } - if (cur.moveToNext()) { - duplicateUserIdsCheck = true; - duplicateUserIds.add(email); - Log.d(Constants.TAG, "more than one user id with the same email"); - } - } - - // convert to long[] - long[] keyIdsArray = new long[keyIds.size()]; - for (int i = 0; i < keyIdsArray.length; i++) { - keyIdsArray[i] = keyIds.get(i); - } - - // allow the user to verify pub key selection - if (missingUserIdsCheck || duplicateUserIdsCheck) { - // build PendingIntent - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS); - intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray); - intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds); - intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, duplicateUserIds); - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } - - if (keyIdsArray.length == 0) { - return null; - } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keyIdsArray); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } - - private Intent getPassphraseBundleIntent(Intent data, long keyId) { - // build PendingIntent for passphrase input - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE); - intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId); - // pass params through to activity that it can be returned again later to repeat pgp operation - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } - - private Intent signImpl(Intent data, ParcelFileDescriptor input, - ParcelFileDescriptor output, AccountSettings accSettings) { - try { - boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); - - // get passphrase from cache, if key has "no" passphrase, this returns an empty String - String passphrase; - if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - } else { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), accSettings.getKeyId()); - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = getPassphraseBundleIntent(data, accSettings.getKeyId()); - return passphraseBundle; - } - - // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); - try { - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); - - // sign-only - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(getContext(), inputData, os); - builder.enableAsciiArmorOutput(asciiArmor) - .signatureHashAlgorithm(accSettings.getHashAlgorithm()) - .signatureForceV3(false) - .signatureKeyId(accSettings.getKeyId()) - .signaturePassphrase(passphrase); - builder.build().execute(); - } finally { - is.close(); - os.close(); - } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input, - ParcelFileDescriptor output, AccountSettings accSettings, - boolean sign) { - try { - boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); - - long[] keyIds; - if (data.hasExtra(OpenPgpApi.EXTRA_KEY_IDS)) { - keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS); - } else if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS)) { - // get key ids based on given user ids - String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS); - // give params through to activity... - Intent result = getKeyIdsFromEmails(data, userIds); - - if (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0) == OpenPgpApi.RESULT_CODE_SUCCESS) { - keyIds = result.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS); - } else { - // if not success -> result contains a PendingIntent for user interaction - return result; - } - } else { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, - "Missing parameter user_ids or key_ids!")); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - - // add own key for encryption - keyIds = Arrays.copyOf(keyIds, keyIds.length + 1); - keyIds[keyIds.length - 1] = accSettings.getKeyId(); - - // build InputData and write into OutputStream - // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); - try { - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); - - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(getContext(), inputData, os); - builder.enableAsciiArmorOutput(asciiArmor) - .compressionId(accSettings.getCompression()) - .symmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm()) - .encryptionKeyIds(keyIds); - - if (sign) { - String passphrase; - if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - } else { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), - accSettings.getKeyId()); - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = getPassphraseBundleIntent(data, accSettings.getKeyId()); - return passphraseBundle; - } - - // sign and encrypt - builder.signatureHashAlgorithm(accSettings.getHashAlgorithm()) - .signatureForceV3(false) - .signatureKeyId(accSettings.getKeyId()) - .signaturePassphrase(passphrase); - } else { - // encrypt only - builder.signatureKeyId(Id.key.none); - } - // execute PGP operation! - builder.build().execute(); - } finally { - is.close(); - os.close(); - } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input, - ParcelFileDescriptor output, Set<Long> allowedKeyIds) { - try { - // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); - - Intent result = new Intent(); - try { - - String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); - - PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os); - builder.allowSymmetricDecryption(false) // no support for symmetric encryption - .allowedKeyIds(allowedKeyIds) // allow only private keys associated with - // accounts of this app - .passphrase(passphrase); - - // TODO: currently does not support binary signed-only content - PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute(); - - if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) { - // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = - getPassphraseBundleIntent(data, decryptVerifyResult.getKeyIdPassphraseNeeded()); - return passphraseBundle; - } else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == - decryptVerifyResult.getStatus()) { - throw new PgpGeneralException("Decryption of symmetric content not supported by API!"); - } - - OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult(); - if (signatureResult != null) { - if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY) { - // If signature is unknown we return an _additional_ PendingIntent - // to retrieve the missing key - Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class); - intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN); - intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId()); - intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - } - - result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); - } - - } finally { - is.close(); - os.close(); - } - - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent getKeyImpl(Intent data) { - try { - long keyId = data.getLongExtra(OpenPgpApi.EXTRA_KEY_ID, 0); - - if (ProviderHelper.getPGPPublicKeyRing(this, keyId) == null) { - Intent result = new Intent(); - - // If keys are not in db we return an additional PendingIntent - // to retrieve the missing key - Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class); - intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN); - intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, keyId); - intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } else { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - - // TODO: also return PendingIntent that opens the key view activity - - return result; - } - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent getKeyIdsImpl(Intent data) { - // get key ids based on given user ids - String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS); - Intent result = getKeyIdsFromEmails(data, userIds); - return result; - } - - /** - * Check requirements: - * - params != null - * - has supported API version - * - is allowed to call the service (access has been granted) - * - * @param data - * @return null if everything is okay, or a Bundle with an error/PendingIntent - */ - private Intent checkRequirements(Intent data) { - // params Bundle is required! - if (data == null) { - Intent result = new Intent(); - OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!"); - result.putExtra(OpenPgpApi.RESULT_ERROR, error); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - - // version code is required and needs to correspond to version code of service! - if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) { - Intent result = new Intent(); - OpenPgpError error = new OpenPgpError - (OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!"); - result.putExtra(OpenPgpApi.RESULT_ERROR, error); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - - // check if caller is allowed to access openpgp keychain - Intent result = isAllowed(data); - if (result != null) { - return result; - } - - return null; - } - - // TODO: multi-threading - private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() { - - @Override - public Intent execute(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output) { - Intent errorResult = checkRequirements(data); - if (errorResult != null) { - return errorResult; - } - - String accName; - if (data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME) != null) { - accName = data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME); - } else { - accName = "default"; - } - final AccountSettings accSettings = getAccSettings(accName); - if (accSettings == null) { - return getCreateAccountIntent(data, accName); - } - - String action = data.getAction(); - if (OpenPgpApi.ACTION_SIGN.equals(action)) { - return signImpl(data, input, output, accSettings); - } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) { - return encryptAndSignImpl(data, input, output, accSettings, false); - } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) { - return encryptAndSignImpl(data, input, output, accSettings, true); - } else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) { - String currentPkg = getCurrentCallingPackage(); - Set<Long> allowedKeyIds = - ProviderHelper.getAllKeyIdsForApp(mContext, - ApiAccounts.buildBaseUri(currentPkg)); - return decryptAndVerifyImpl(data, input, output, allowedKeyIds); - } else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) { - return getKeyImpl(data); - } else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) { - return getKeyIdsImpl(data); - } else { - return null; - } - } - - }; - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java deleted file mode 100644 index 16a800022..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote; - -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.Signature; -import android.net.Uri; -import android.os.Binder; - -import org.openintents.openpgp.OpenPgpError; -import org.openintents.openpgp.util.OpenPgpApi; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Abstract service class for remote APIs that handle app registration and user input. - */ -public abstract class RemoteService extends Service { - Context mContext; - - public Context getContext() { - return mContext; - } - - protected Intent isAllowed(Intent data) { - try { - if (isCallerAllowed(false)) { - return null; - } else { - String packageName = getCurrentCallingPackage(); - Log.d(Constants.TAG, "isAllowed packageName: " + packageName); - - byte[] packageSignature; - try { - packageSignature = getPackageSignature(packageName); - } catch (NameNotFoundException e) { - Log.e(Constants.TAG, "Should not happen, returning!", e); - // return error - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - return result; - } - Log.e(Constants.TAG, "Not allowed to use service! return PendingIntent for registration!"); - - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_REGISTER); - intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName); - intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature); - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - - return result; - } - } catch (WrongPackageSignatureException e) { - Log.e(Constants.TAG, "wrong signature!", e); - - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE); - intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, - getString(R.string.api_error_wrong_signature)); - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - - return result; - } - } - - private byte[] getPackageSignature(String packageName) throws NameNotFoundException { - PackageInfo pkgInfo = getPackageManager().getPackageInfo(packageName, - PackageManager.GET_SIGNATURES); - Signature[] signatures = pkgInfo.signatures; - // TODO: Only first signature?! - byte[] packageSignature = signatures[0].toByteArray(); - - return packageSignature; - } - - /** - * Returns package name associated with the UID, which is assigned to the process that sent you the - * current transaction that is being processed :) - * - * @return package name - */ - protected String getCurrentCallingPackage() { - // TODO: - // callingPackages contains more than one entry when sharedUserId has been used... - String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); - String currentPkg = callingPackages[0]; - Log.d(Constants.TAG, "currentPkg: " + currentPkg); - - return currentPkg; - } - - /** - * Retrieves AccountSettings from database for the application calling this remote service - * - * @return - */ - protected AccountSettings getAccSettings(String accountName) { - String currentPkg = getCurrentCallingPackage(); - Log.d(Constants.TAG, "accountName: " + accountName); - - Uri uri = KeychainContract.ApiAccounts.buildByPackageAndAccountUri(currentPkg, accountName); - - AccountSettings settings = ProviderHelper.getApiAccountSettings(this, uri); - - return settings; // can be null! - } - - protected Intent getCreateAccountIntent(Intent data, String accountName) { - String packageName = getCurrentCallingPackage(); - Log.d(Constants.TAG, "accountName: " + accountName); - - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_CREATE_ACCOUNT); - intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName); - intent.putExtra(RemoteServiceActivity.EXTRA_ACC_NAME, accountName); - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - - return result; - } - - /** - * Checks if process that binds to this service (i.e. the package name corresponding to the - * process) is in the list of allowed package names. - * - * @param allowOnlySelf allow only Keychain app itself - * @return true if process is allowed to use this service - * @throws WrongPackageSignatureException - */ - private boolean isCallerAllowed(boolean allowOnlySelf) throws WrongPackageSignatureException { - return isUidAllowed(Binder.getCallingUid(), allowOnlySelf); - } - - private boolean isUidAllowed(int uid, boolean allowOnlySelf) - throws WrongPackageSignatureException { - if (android.os.Process.myUid() == uid) { - return true; - } - if (allowOnlySelf) { // barrier - return false; - } - - String[] callingPackages = getPackageManager().getPackagesForUid(uid); - - // is calling package allowed to use this service? - for (int i = 0; i < callingPackages.length; i++) { - String currentPkg = callingPackages[i]; - - if (isPackageAllowed(currentPkg)) { - return true; - } - } - - Log.d(Constants.TAG, "Uid is NOT allowed!"); - return false; - } - - /** - * Checks if packageName is a registered app for the API. Does not return true for own package! - * - * @param packageName - * @return - * @throws WrongPackageSignatureException - */ - private boolean isPackageAllowed(String packageName) throws WrongPackageSignatureException { - Log.d(Constants.TAG, "isPackageAllowed packageName: " + packageName); - - ArrayList<String> allowedPkgs = ProviderHelper.getRegisteredApiApps(this); - Log.d(Constants.TAG, "allowed: " + allowedPkgs); - - // check if package is allowed to use our service - if (allowedPkgs.contains(packageName)) { - Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName); - - // check package signature - byte[] currentSig; - try { - currentSig = getPackageSignature(packageName); - } catch (NameNotFoundException e) { - throw new WrongPackageSignatureException(e.getMessage()); - } - - byte[] storedSig = ProviderHelper.getApiAppSignature(this, packageName); - if (Arrays.equals(currentSig, storedSig)) { - Log.d(Constants.TAG, - "Package signature is correct! (equals signature from database)"); - return true; - } else { - throw new WrongPackageSignatureException( - "PACKAGE NOT ALLOWED! Signature wrong! (Signature not " + - "equals signature from database)"); - } - } - - Log.d(Constants.TAG, "Package is NOT allowed! packageName: " + packageName); - return false; - } - - @Override - public void onCreate() { - super.onCreate(); - mContext = this; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/WrongPackageSignatureException.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/WrongPackageSignatureException.java deleted file mode 100644 index 6f44a65e9..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/WrongPackageSignatureException.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote; - -public class WrongPackageSignatureException extends Exception { - - private static final long serialVersionUID = -8294642703122196028L; - - public WrongPackageSignatureException(String message) { - super(message); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java deleted file mode 100644 index 123ed526f..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote.ui; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.remote.AccountSettings; -import org.sufficientlysecure.keychain.util.Log; - -public class AccountSettingsActivity extends ActionBarActivity { - private Uri mAccountUri; - - private AccountSettingsFragment mAccountSettingsFragment; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Inflate a "Done" custom action bar - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.api_settings_save, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // "Done" - save(); - } - }); - - setContentView(R.layout.api_account_settings_activity); - - mAccountSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById( - R.id.api_account_settings_fragment); - - Intent intent = getIntent(); - mAccountUri = intent.getData(); - if (mAccountUri == null) { - Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!"); - finish(); - return; - } else { - Log.d(Constants.TAG, "uri: " + mAccountUri); - loadData(mAccountUri); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.api_account_settings, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_account_settings_delete: - deleteAccount(); - return true; - case R.id.menu_account_settings_cancel: - finish(); - return true; - } - return super.onOptionsItemSelected(item); - } - - private void loadData(Uri accountUri) { - AccountSettings settings = ProviderHelper.getApiAccountSettings(this, accountUri); - mAccountSettingsFragment.setAccSettings(settings); - } - - private void deleteAccount() { - if (getContentResolver().delete(mAccountUri, null, null) <= 0) { - throw new RuntimeException(); - } - finish(); - } - - private void save() { - ProviderHelper.updateApiAccount(this, mAccountSettingsFragment.getAccSettings(), mAccountUri); - finish(); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java deleted file mode 100644 index 0a3ec3c3b..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote.ui; - -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.Spinner; -import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.remote.AccountSettings; -import org.sufficientlysecure.keychain.ui.EditKeyActivity; -import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment; -import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter; -import org.sufficientlysecure.keychain.util.AlgorithmNames; - -public class AccountSettingsFragment extends Fragment implements - SelectSecretKeyLayoutFragment.SelectSecretKeyCallback { - - private static final int REQUEST_CODE_CREATE_KEY = 0x00008884; - - // model - private AccountSettings mAccSettings; - - // view - private TextView mAccNameView; - private Spinner mEncryptionAlgorithm; - private Spinner mHashAlgorithm; - private Spinner mCompression; - - private SelectSecretKeyLayoutFragment mSelectKeyFragment; - private BootstrapButton mCreateKeyButton; - - KeyValueSpinnerAdapter mEncryptionAdapter; - KeyValueSpinnerAdapter mHashAdapter; - KeyValueSpinnerAdapter mCompressionAdapter; - - public AccountSettings getAccSettings() { - return mAccSettings; - } - - public void setAccSettings(AccountSettings accountSettings) { - this.mAccSettings = accountSettings; - - mAccNameView.setText(accountSettings.getAccountName()); - mSelectKeyFragment.selectKey(accountSettings.getKeyId()); - mEncryptionAlgorithm.setSelection(mEncryptionAdapter.getPosition(accountSettings - .getEncryptionAlgorithm())); - mHashAlgorithm.setSelection(mHashAdapter.getPosition(accountSettings.getHashAlgorithm())); - mCompression.setSelection(mCompressionAdapter.getPosition(accountSettings.getCompression())); - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.api_account_settings_fragment, container, false); - initView(view); - return view; - } - - /** - * Set error String on key selection - * - * @param error - */ - public void setErrorOnSelectKeyFragment(String error) { - mSelectKeyFragment.setError(error); - } - - private void initView(View view) { - mSelectKeyFragment = (SelectSecretKeyLayoutFragment) getFragmentManager().findFragmentById( - R.id.api_account_settings_select_key_fragment); - mSelectKeyFragment.setCallback(this); - - mAccNameView = (TextView) view.findViewById(R.id.api_account_settings_acc_name); - mEncryptionAlgorithm = (Spinner) view - .findViewById(R.id.api_account_settings_encryption_algorithm); - mHashAlgorithm = (Spinner) view.findViewById(R.id.api_account_settings_hash_algorithm); - mCompression = (Spinner) view.findViewById(R.id.api_account_settings_compression); - mCreateKeyButton = (BootstrapButton) view.findViewById(R.id.api_account_settings_create_key); - - mCreateKeyButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - createKey(); - } - }); - - AlgorithmNames algorithmNames = new AlgorithmNames(getActivity()); - - mEncryptionAdapter = new KeyValueSpinnerAdapter(getActivity(), - algorithmNames.getEncryptionNames()); - mEncryptionAlgorithm.setAdapter(mEncryptionAdapter); - mEncryptionAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - mAccSettings.setEncryptionAlgorithm((int) id); - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - } - }); - - mHashAdapter = new KeyValueSpinnerAdapter(getActivity(), algorithmNames.getHashNames()); - mHashAlgorithm.setAdapter(mHashAdapter); - mHashAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - mAccSettings.setHashAlgorithm((int) id); - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - } - }); - - mCompressionAdapter = new KeyValueSpinnerAdapter(getActivity(), - algorithmNames.getCompressionNames()); - mCompression.setAdapter(mCompressionAdapter); - mCompression.setOnItemSelectedListener(new OnItemSelectedListener() { - - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - mAccSettings.setCompression((int) id); - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - } - }); - } - - private void createKey() { - Intent intent = new Intent(getActivity(), EditKeyActivity.class); - intent.setAction(EditKeyActivity.ACTION_CREATE_KEY); - intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true); - // set default user id to account name - intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, mAccSettings.getAccountName()); - startActivityForResult(intent, REQUEST_CODE_CREATE_KEY); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CODE_CREATE_KEY: { - if (resultCode == Activity.RESULT_OK) { - // select newly created key - long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), data.getData()); - mSelectKeyFragment.selectKey(masterKeyId); - } - break; - } - - default: - super.onActivityResult(requestCode, resultCode, data); - - break; - } - } - - /** - * callback from select secret key fragment - */ - @Override - public void onKeySelected(long secretKeyId) { - mAccSettings.setKeyId(secretKeyId); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountsListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountsListFragment.java deleted file mode 100644 index 4d99e1923..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountsListFragment.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote.ui; - -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.ListFragment; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.support.v4.widget.CursorAdapter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ListView; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.ui.widget.FixedListView; -import org.sufficientlysecure.keychain.util.Log; - -public class AccountsListFragment extends ListFragment implements - LoaderManager.LoaderCallbacks<Cursor> { - - private static final String ARG_DATA_URI = "uri"; - - // This is the Adapter being used to display the list's data. - AccountsAdapter mAdapter; - - private Uri mDataUri; - - /** - * Creates new instance of this fragment - */ - public static AccountsListFragment newInstance(Uri dataUri) { - AccountsListFragment frag = new AccountsListFragment(); - - Bundle args = new Bundle(); - args.putParcelable(ARG_DATA_URI, dataUri); - - frag.setArguments(args); - - return frag; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View layout = super.onCreateView(inflater, container, - savedInstanceState); - ListView lv = (ListView) layout.findViewById(android.R.id.list); - ViewGroup parent = (ViewGroup) lv.getParent(); - - /* - * http://stackoverflow.com/a/15880684 - * Remove ListView and add FixedListView in its place. - * This is done here programatically to be still able to use the progressBar of ListFragment. - * - * We want FixedListView to be able to put this ListFragment inside a ScrollView - */ - int lvIndex = parent.indexOfChild(lv); - parent.removeViewAt(lvIndex); - FixedListView newLv = new FixedListView(getActivity()); - newLv.setId(android.R.id.list); - parent.addView(newLv, lvIndex, lv.getLayoutParams()); - return layout; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mDataUri = getArguments().getParcelable(ARG_DATA_URI); - - getListView().setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { - String selectedAccountName = mAdapter.getItemAccountName(position); - Uri accountUri = mDataUri.buildUpon().appendEncodedPath(selectedAccountName).build(); - Log.d(Constants.TAG, "accountUri: " + accountUri); - - // edit account settings - Intent intent = new Intent(getActivity(), AccountSettingsActivity.class); - intent.setData(accountUri); - startActivity(intent); - } - }); - - // Give some text to display if there is no data. In a real - // application this would come from a resource. - setEmptyText(getString(R.string.api_settings_accounts_empty)); - - // We have a menu item to show in action bar. - setHasOptionsMenu(true); - - // Create an empty adapter we will use to display the loaded data. - mAdapter = new AccountsAdapter(getActivity(), null, 0); - setListAdapter(mAdapter); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - getLoaderManager().initLoader(0, null, this); - } - - // These are the Contacts rows that we will retrieve. - static final String[] PROJECTION = new String[]{ - KeychainContract.ApiAccounts._ID, // 0 - KeychainContract.ApiAccounts.ACCOUNT_NAME // 1 - }; - - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - // This is called when a new Loader needs to be created. This - // sample only has one Loader, so we don't care about the ID. - - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), mDataUri, PROJECTION, null, null, - KeychainContract.ApiAccounts.ACCOUNT_NAME + " COLLATE LOCALIZED ASC"); - } - - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - mAdapter.swapCursor(data); - } - - public void onLoaderReset(Loader<Cursor> loader) { - // This is called when the last Cursor provided to onLoadFinished() - // above is about to be closed. We need to make sure we are no - // longer using it. - mAdapter.swapCursor(null); - } - - private class AccountsAdapter extends CursorAdapter { - private LayoutInflater mInflater; - - public AccountsAdapter(Context context, Cursor c, int flags) { - super(context, c, flags); - - mInflater = LayoutInflater.from(context); - } - - /** - * Similar to CursorAdapter.getItemId(). - * Required to build Uris for api accounts, which are not based on row ids - * - * @param position - * @return - */ - public String getItemAccountName(int position) { - if (mDataValid && mCursor != null) { - if (mCursor.moveToPosition(position)) { - return mCursor.getString(1); - } else { - return null; - } - } else { - return null; - } - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - TextView text = (TextView) view.findViewById(R.id.api_accounts_adapter_item_name); - - String accountName = cursor.getString(1); - text.setText(accountName); - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.api_accounts_adapter_list_item, null); - } - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java deleted file mode 100644 index 818c296c1..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote.ui; - -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.view.Menu; -import android.view.MenuItem; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.remote.AppSettings; -import org.sufficientlysecure.keychain.util.Log; - -public class AppSettingsActivity extends ActionBarActivity { - private Uri mAppUri; - - private AppSettingsFragment mSettingsFragment; - private AccountsListFragment mAccountsListFragment; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // let the actionbar look like Android's contact app - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setIcon(android.R.color.transparent); - actionBar.setHomeButtonEnabled(true); - - setContentView(R.layout.api_app_settings_activity); - - mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( - R.id.api_app_settings_fragment); - - Intent intent = getIntent(); - mAppUri = intent.getData(); - if (mAppUri == null) { - Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!"); - finish(); - return; - } else { - Log.d(Constants.TAG, "uri: " + mAppUri); - loadData(savedInstanceState, mAppUri); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.api_app_settings, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_api_settings_revoke: - revokeAccess(); - return true; - } - return super.onOptionsItemSelected(item); - } - - private void loadData(Bundle savedInstanceState, Uri appUri) { - AppSettings settings = ProviderHelper.getApiAppSettings(this, appUri); - mSettingsFragment.setAppSettings(settings); - - String appName; - PackageManager pm = getPackageManager(); - try { - ApplicationInfo ai = pm.getApplicationInfo(settings.getPackageName(), 0); - appName = (String) pm.getApplicationLabel(ai); - } catch (PackageManager.NameNotFoundException e) { - // fallback - appName = settings.getPackageName(); - } - setTitle(appName); - - Uri accountsUri = appUri.buildUpon().appendPath(KeychainContract.PATH_ACCOUNTS).build(); - Log.d(Constants.TAG, "accountsUri: " + accountsUri); - startListFragment(savedInstanceState, accountsUri); - } - - private void startListFragment(Bundle savedInstanceState, Uri dataUri) { - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; - } - - // Create an instance of the fragment - mAccountsListFragment = AccountsListFragment.newInstance(dataUri); - - // Add the fragment to the 'fragment_container' FrameLayout - // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! - getSupportFragmentManager().beginTransaction() - .replace(R.id.api_accounts_list_fragment, mAccountsListFragment) - .commitAllowingStateLoss(); - // do it immediately! - getSupportFragmentManager().executePendingTransactions(); - } - - private void revokeAccess() { - if (getContentResolver().delete(mAppUri, null, null) <= 0) { - throw new RuntimeException(); - } - finish(); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java deleted file mode 100644 index a6db02708..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote.ui; - -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.remote.AppSettings; -import org.sufficientlysecure.keychain.util.Log; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -public class AppSettingsFragment extends Fragment { - - // model - private AppSettings mAppSettings; - - // view - private TextView mAppNameView; - private ImageView mAppIconView; - private TextView mPackageName; - private TextView mPackageSignature; - - public AppSettings getAppSettings() { - return mAppSettings; - } - - public void setAppSettings(AppSettings appSettings) { - this.mAppSettings = appSettings; - updateView(appSettings); - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.api_app_settings_fragment, container, false); - mAppNameView = (TextView) view.findViewById(R.id.api_app_settings_app_name); - mAppIconView = (ImageView) view.findViewById(R.id.api_app_settings_app_icon); - mPackageName = (TextView) view.findViewById(R.id.api_app_settings_package_name); - mPackageSignature = (TextView) view.findViewById(R.id.api_app_settings_package_signature); - return view; - } - - private void updateView(AppSettings appSettings) { - // get application name and icon from package manager - String appName; - Drawable appIcon = null; - PackageManager pm = getActivity().getApplicationContext().getPackageManager(); - try { - ApplicationInfo ai = pm.getApplicationInfo(appSettings.getPackageName(), 0); - - appName = (String) pm.getApplicationLabel(ai); - appIcon = pm.getApplicationIcon(ai); - } catch (NameNotFoundException e) { - // fallback - appName = appSettings.getPackageName(); - } - mAppNameView.setText(appName); - mAppIconView.setImageDrawable(appIcon); - - // advanced info: package name - mPackageName.setText(appSettings.getPackageName()); - - // advanced info: package signature SHA-256 - try { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - md.update(appSettings.getPackageSignature()); - byte[] digest = md.digest(); - String signature = new String(Hex.encode(digest)); - - mPackageSignature.setText(signature); - } catch (NoSuchAlgorithmException e) { - Log.e(Constants.TAG, "Should not happen!", e); - } - } - - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java deleted file mode 100644 index f86d279f0..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote.ui; - -import android.os.Bundle; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.DrawerActivity; - -public class AppsListActivity extends DrawerActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.api_apps_list_activity); - - setupDrawerNavigation(savedInstanceState); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java deleted file mode 100644 index 9d0e6d3ef..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote.ui; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.ListFragment; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.support.v4.widget.CursorAdapter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ImageView; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; - -public class AppsListFragment extends ListFragment implements - LoaderManager.LoaderCallbacks<Cursor> { - - // This is the Adapter being used to display the list's data. - RegisteredAppsAdapter mAdapter; - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - getListView().setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { - String selectedPackageName = mAdapter.getItemPackageName(position); - // edit app settings - Intent intent = new Intent(getActivity(), AppSettingsActivity.class); - intent.setData(KeychainContract.ApiApps.buildByPackageNameUri(selectedPackageName)); - startActivity(intent); - } - }); - - // Give some text to display if there is no data. In a real - // application this would come from a resource. - setEmptyText(getString(R.string.api_no_apps)); - - // We have a menu item to show in action bar. - setHasOptionsMenu(true); - - // Create an empty adapter we will use to display the loaded data. - mAdapter = new RegisteredAppsAdapter(getActivity(), null, 0); - setListAdapter(mAdapter); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - getLoaderManager().initLoader(0, null, this); - } - - // These are the Contacts rows that we will retrieve. - static final String[] PROJECTION = new String[]{ - ApiApps._ID, // 0 - ApiApps.PACKAGE_NAME // 1 - }; - - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - // This is called when a new Loader needs to be created. This - // sample only has one Loader, so we don't care about the ID. - // First, pick the base URI to use depending on whether we are - // currently filtering. - Uri baseUri = ApiApps.CONTENT_URI; - - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null, - ApiApps.PACKAGE_NAME + " COLLATE LOCALIZED ASC"); - } - - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - mAdapter.swapCursor(data); - } - - public void onLoaderReset(Loader<Cursor> loader) { - // This is called when the last Cursor provided to onLoadFinished() - // above is about to be closed. We need to make sure we are no - // longer using it. - mAdapter.swapCursor(null); - } - - private class RegisteredAppsAdapter extends CursorAdapter { - - private LayoutInflater mInflater; - private PackageManager mPM; - - public RegisteredAppsAdapter(Context context, Cursor c, int flags) { - super(context, c, flags); - - mInflater = LayoutInflater.from(context); - mPM = context.getApplicationContext().getPackageManager(); - } - - /** - * Similar to CursorAdapter.getItemId(). - * Required to build Uris for api apps, which are not based on row ids - * - * @param position - * @return - */ - public String getItemPackageName(int position) { - if (mDataValid && mCursor != null) { - if (mCursor.moveToPosition(position)) { - return mCursor.getString(1); - } else { - return null; - } - } else { - return null; - } - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - TextView text = (TextView) view.findViewById(R.id.api_apps_adapter_item_name); - ImageView icon = (ImageView) view.findViewById(R.id.api_apps_adapter_item_icon); - - String packageName = cursor.getString(cursor.getColumnIndex(ApiApps.PACKAGE_NAME)); - if (packageName != null) { - // get application name - try { - ApplicationInfo ai = mPM.getApplicationInfo(packageName, 0); - - text.setText(mPM.getApplicationLabel(ai)); - icon.setImageDrawable(mPM.getApplicationIcon(ai)); - } catch (final PackageManager.NameNotFoundException e) { - // fallback - text.setText(packageName); - } - } else { - // fallback - text.setText(packageName); - } - - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.api_apps_adapter_list_item, null); - } - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java deleted file mode 100644 index ab95f2691..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote.ui; - -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.support.v7.app.ActionBarActivity; -import android.view.View; - -import org.openintents.openpgp.util.OpenPgpApi; -import org.sufficientlysecure.htmltextview.HtmlTextView; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.remote.AccountSettings; -import org.sufficientlysecure.keychain.remote.AppSettings; -import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment; -import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; - -public class RemoteServiceActivity extends ActionBarActivity { - - public static final String ACTION_REGISTER = Constants.INTENT_PREFIX + "API_ACTIVITY_REGISTER"; - public static final String ACTION_CREATE_ACCOUNT = Constants.INTENT_PREFIX - + "API_ACTIVITY_CREATE_ACCOUNT"; - public static final String ACTION_CACHE_PASSPHRASE = Constants.INTENT_PREFIX - + "API_ACTIVITY_CACHE_PASSPHRASE"; - public static final String ACTION_SELECT_PUB_KEYS = Constants.INTENT_PREFIX - + "API_ACTIVITY_SELECT_PUB_KEYS"; - public static final String ACTION_ERROR_MESSAGE = Constants.INTENT_PREFIX - + "API_ACTIVITY_ERROR_MESSAGE"; - - public static final String EXTRA_MESSENGER = "messenger"; - - public static final String EXTRA_DATA = "data"; - - // passphrase action - public static final String EXTRA_SECRET_KEY_ID = "secret_key_id"; - // register action - public static final String EXTRA_PACKAGE_NAME = "package_name"; - public static final String EXTRA_PACKAGE_SIGNATURE = "package_signature"; - // create acc action - public static final String EXTRA_ACC_NAME = "acc_name"; - // select pub keys action - public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids"; - public static final String EXTRA_MISSING_USER_IDS = "missing_user_ids"; - public static final String EXTRA_DUBLICATE_USER_IDS = "dublicate_user_ids"; - // error message - public static final String EXTRA_ERROR_MESSAGE = "error_message"; - - // register view - private AppSettingsFragment mAppSettingsFragment; - // create acc view - private AccountSettingsFragment mAccSettingsFragment; - // select pub keys view - private SelectPublicKeyFragment mSelectFragment; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - handleActions(getIntent(), savedInstanceState); - } - - protected void handleActions(Intent intent, Bundle savedInstanceState) { - - String action = intent.getAction(); - final Bundle extras = intent.getExtras(); - - - if (ACTION_REGISTER.equals(action)) { - final String packageName = extras.getString(EXTRA_PACKAGE_NAME); - final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE); - Log.d(Constants.TAG, "ACTION_REGISTER packageName: " + packageName); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.api_register_allow, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Allow - - ProviderHelper.insertApiApp(RemoteServiceActivity.this, - mAppSettingsFragment.getAppSettings()); - - // give data through for new service call - Intent resultData = extras.getParcelable(EXTRA_DATA); - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); - RemoteServiceActivity.this.finish(); - } - }, R.string.api_register_disallow, R.drawable.ic_action_cancel, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Disallow - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); - } - } - ); - - setContentView(R.layout.api_remote_register_app); - - mAppSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( - R.id.api_app_settings_fragment); - - AppSettings settings = new AppSettings(packageName, packageSignature); - mAppSettingsFragment.setAppSettings(settings); - } else if (ACTION_CREATE_ACCOUNT.equals(action)) { - final String packageName = extras.getString(EXTRA_PACKAGE_NAME); - final String accName = extras.getString(EXTRA_ACC_NAME); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.api_settings_save, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Save - - // user needs to select a key! - if (mAccSettingsFragment.getAccSettings().getKeyId() == Id.key.none) { - mAccSettingsFragment.setErrorOnSelectKeyFragment( - getString(R.string.api_register_error_select_key)); - } else { - ProviderHelper.insertApiAccount(RemoteServiceActivity.this, - KeychainContract.ApiAccounts.buildBaseUri(packageName), - mAccSettingsFragment.getAccSettings()); - - // give data through for new service call - Intent resultData = extras.getParcelable(EXTRA_DATA); - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); - RemoteServiceActivity.this.finish(); - } - } - }, R.string.api_settings_cancel, R.drawable.ic_action_cancel, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Cancel - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); - } - } - ); - - setContentView(R.layout.api_remote_create_account); - - mAccSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById( - R.id.api_account_settings_fragment); - - AccountSettings settings = new AccountSettings(accName); - mAccSettingsFragment.setAccSettings(settings); - } else if (ACTION_CACHE_PASSPHRASE.equals(action)) { - long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID); - final Intent resultData = extras.getParcelable(EXTRA_DATA); - - PassphraseDialogFragment.show(this, secretKeyId, - new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - // return given params again, for calling the service method again - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); - } else { - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - } - - RemoteServiceActivity.this.finish(); - } - }); - - } else if (ACTION_SELECT_PUB_KEYS.equals(action)) { - long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); - ArrayList<String> missingUserIds = intent - .getStringArrayListExtra(EXTRA_MISSING_USER_IDS); - ArrayList<String> dublicateUserIds = intent - .getStringArrayListExtra(EXTRA_DUBLICATE_USER_IDS); - - // TODO: do this with spannable instead of HTML to prevent parsing failures with weird user ids - String text = "<b>" + getString(R.string.api_select_pub_keys_text) + "</b>"; - text += "<br/><br/>"; - if (missingUserIds != null && missingUserIds.size() > 0) { - text += getString(R.string.api_select_pub_keys_missing_text); - text += "<br/>"; - text += "<ul>"; - for (String userId : missingUserIds) { - text += "<li>" + userId + "</li>"; - } - text += "</ul>"; - text += "<br/>"; - } - if (dublicateUserIds != null && dublicateUserIds.size() > 0) { - text += getString(R.string.api_select_pub_keys_dublicates_text); - text += "<br/>"; - text += "<ul>"; - for (String userId : dublicateUserIds) { - text += "<li>" + userId + "</li>"; - } - text += "</ul>"; - } - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // add key ids to params Bundle for new request - Intent resultData = extras.getParcelable(EXTRA_DATA); - resultData.putExtra(OpenPgpApi.EXTRA_KEY_IDS, - mSelectFragment.getSelectedMasterKeyIds()); - - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); - RemoteServiceActivity.this.finish(); - } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { - @Override - public void onClick(View v) { - // cancel - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); - } - } - ); - - setContentView(R.layout.api_remote_select_pub_keys); - - // set text on view - HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_select_pub_keys_text); - textView.setHtmlFromString(text); - - /* Load select pub keys fragment */ - // Check that the activity is using the layout version with - // the fragment_container FrameLayout - if (findViewById(R.id.api_select_pub_keys_fragment_container) != null) { - - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; - } - - // Create an instance of the fragment - mSelectFragment = SelectPublicKeyFragment.newInstance(selectedMasterKeyIds); - - // Add the fragment to the 'fragment_container' FrameLayout - getSupportFragmentManager().beginTransaction() - .add(R.id.api_select_pub_keys_fragment_container, mSelectFragment).commit(); - } - } else if (ACTION_ERROR_MESSAGE.equals(action)) { - String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE); - - String text = "<font color=\"red\">" + errorMessage + "</font>"; - - // Inflate a "Done" custom action bar view - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, - new View.OnClickListener() { - - @Override - public void onClick(View v) { - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); - } - }); - - setContentView(R.layout.api_remote_error_message); - - // set text on view - HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_app_error_message_text); - textView.setHtmlFromString(text); - } else { - Log.e(Constants.TAG, "Action does not exist!"); - setResult(RESULT_CANCELED); - finish(); - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java deleted file mode 100644 index 1c6aa7971..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ /dev/null @@ -1,905 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.service; - -import android.app.IntentService; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; - -import org.spongycastle.bcpg.sig.KeyFlags; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.PGPUtil; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.FileHelper; -import org.sufficientlysecure.keychain.helper.OtherHelper; -import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; -import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.pgp.PgpImportExport; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; -import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; -import org.sufficientlysecure.keychain.util.HkpKeyServer; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.KeychainServiceListener; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; -import org.sufficientlysecure.keychain.util.ProgressScaler; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * This Service contains all important long lasting operations for APG. It receives Intents with - * data from the activities or other apps, queues these intents, executes them, and stops itself - * after doing them. - */ -public class KeychainIntentService extends IntentService - implements ProgressDialogUpdater, KeychainServiceListener { - - /* extras that can be given by intent */ - public static final String EXTRA_MESSENGER = "messenger"; - public static final String EXTRA_DATA = "data"; - - /* possible actions */ - public static final String ACTION_ENCRYPT_SIGN = Constants.INTENT_PREFIX + "ENCRYPT_SIGN"; - - public static final String ACTION_DECRYPT_VERIFY = Constants.INTENT_PREFIX + "DECRYPT_VERIFY"; - - public static final String ACTION_SAVE_KEYRING = Constants.INTENT_PREFIX + "SAVE_KEYRING"; - public static final String ACTION_GENERATE_KEY = Constants.INTENT_PREFIX + "GENERATE_KEY"; - public static final String ACTION_GENERATE_DEFAULT_RSA_KEYS = Constants.INTENT_PREFIX - + "GENERATE_DEFAULT_RSA_KEYS"; - - public static final String ACTION_DELETE_FILE_SECURELY = Constants.INTENT_PREFIX - + "DELETE_FILE_SECURELY"; - - public static final String ACTION_IMPORT_KEYRING = Constants.INTENT_PREFIX + "IMPORT_KEYRING"; - public static final String ACTION_EXPORT_KEYRING = Constants.INTENT_PREFIX + "EXPORT_KEYRING"; - - public static final String ACTION_UPLOAD_KEYRING = Constants.INTENT_PREFIX + "UPLOAD_KEYRING"; - public static final String ACTION_DOWNLOAD_AND_IMPORT_KEYS = Constants.INTENT_PREFIX + "QUERY_KEYRING"; - - public static final String ACTION_CERTIFY_KEYRING = Constants.INTENT_PREFIX + "SIGN_KEYRING"; - - /* keys for data bundle */ - - // encrypt, decrypt, import export - public static final String TARGET = "target"; - // possible targets: - public static final int TARGET_BYTES = 1; - public static final int TARGET_URI = 2; - - // encrypt - public static final String ENCRYPT_SIGNATURE_KEY_ID = "secret_key_id"; - public static final String ENCRYPT_USE_ASCII_ARMOR = "use_ascii_armor"; - public static final String ENCRYPT_ENCRYPTION_KEYS_IDS = "encryption_keys_ids"; - public static final String ENCRYPT_COMPRESSION_ID = "compression_id"; - public static final String ENCRYPT_MESSAGE_BYTES = "message_bytes"; - public static final String ENCRYPT_INPUT_FILE = "input_file"; - public static final String ENCRYPT_OUTPUT_FILE = "output_file"; - public static final String ENCRYPT_SYMMETRIC_PASSPHRASE = "passphrase"; - - // decrypt/verify - public static final String DECRYPT_CIPHERTEXT_BYTES = "ciphertext_bytes"; - public static final String DECRYPT_PASSPHRASE = "passphrase"; - - // save keyring - public static final String SAVE_KEYRING_PARCEL = "save_parcel"; - public static final String SAVE_KEYRING_CAN_SIGN = "can_sign"; - - - // generate key - public static final String GENERATE_KEY_ALGORITHM = "algorithm"; - public static final String GENERATE_KEY_KEY_SIZE = "key_size"; - public static final String GENERATE_KEY_SYMMETRIC_PASSPHRASE = "passphrase"; - public static final String GENERATE_KEY_MASTER_KEY = "master_key"; - - // delete file securely - public static final String DELETE_FILE = "deleteFile"; - - // import key - public static final String IMPORT_KEY_LIST = "import_key_list"; - - // export key - public static final String EXPORT_OUTPUT_STREAM = "export_output_stream"; - public static final String EXPORT_FILENAME = "export_filename"; - public static final String EXPORT_SECRET = "export_secret"; - public static final String EXPORT_ALL = "export_all"; - public static final String EXPORT_KEY_RING_MASTER_KEY_ID = "export_key_ring_id"; - - // upload key - public static final String UPLOAD_KEY_SERVER = "upload_key_server"; - - // query key - public static final String DOWNLOAD_KEY_SERVER = "query_key_server"; - public static final String DOWNLOAD_KEY_LIST = "query_key_id"; - - // sign key - public static final String CERTIFY_KEY_MASTER_KEY_ID = "sign_key_master_key_id"; - public static final String CERTIFY_KEY_PUB_KEY_ID = "sign_key_pub_key_id"; - public static final String CERTIFY_KEY_UIDS = "sign_key_uids"; - - /* - * possible data keys as result send over messenger - */ - // keys - public static final String RESULT_NEW_KEY = "new_key"; - public static final String RESULT_KEY_USAGES = "new_key_usages"; - - // encrypt - public static final String RESULT_BYTES = "encrypted_data"; - - // decrypt/verify - public static final String RESULT_DECRYPTED_BYTES = "decrypted_data"; - public static final String RESULT_DECRYPT_VERIFY_RESULT = "signature"; - - // import - public static final String RESULT_IMPORT_ADDED = "added"; - public static final String RESULT_IMPORT_UPDATED = "updated"; - public static final String RESULT_IMPORT_BAD = "bad"; - - // export - public static final String RESULT_EXPORT = "exported"; - - Messenger mMessenger; - - private boolean mIsCanceled; - - public KeychainIntentService() { - super("KeychainIntentService"); - } - - @Override - public void onDestroy() { - super.onDestroy(); - this.mIsCanceled = true; - } - - /** - * The IntentService calls this method from the default worker thread with the intent that - * started the service. When this method returns, IntentService stops the service, as - * appropriate. - */ - @Override - protected void onHandleIntent(Intent intent) { - Bundle extras = intent.getExtras(); - if (extras == null) { - Log.e(Constants.TAG, "Extras bundle is null!"); - return; - } - - if (!(extras.containsKey(EXTRA_MESSENGER) || extras.containsKey(EXTRA_DATA) || (intent - .getAction() == null))) { - Log.e(Constants.TAG, - "Extra bundle must contain a messenger, a data bundle, and an action!"); - return; - } - - Uri dataUri = intent.getData(); - - mMessenger = (Messenger) extras.get(EXTRA_MESSENGER); - Bundle data = extras.getBundle(EXTRA_DATA); - - OtherHelper.logDebugBundle(data, "EXTRA_DATA"); - - String action = intent.getAction(); - - // executeServiceMethod action from extra bundle - if (ACTION_ENCRYPT_SIGN.equals(action)) { - try { - /* Input */ - int target = data.getInt(TARGET); - - long signatureKeyId = data.getLong(ENCRYPT_SIGNATURE_KEY_ID); - String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE); - - boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR); - long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS); - int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID); - InputStream inStream; - long inLength; - InputData inputData; - OutputStream outStream; -// String streamFilename = null; - switch (target) { - case TARGET_BYTES: /* encrypting bytes directly */ - byte[] bytes = data.getByteArray(ENCRYPT_MESSAGE_BYTES); - - inStream = new ByteArrayInputStream(bytes); - inLength = bytes.length; - - inputData = new InputData(inStream, inLength); - outStream = new ByteArrayOutputStream(); - - break; - case TARGET_URI: /* encrypting file */ - String inputFile = data.getString(ENCRYPT_INPUT_FILE); - String outputFile = data.getString(ENCRYPT_OUTPUT_FILE); - - // check if storage is ready - if (!FileHelper.isStorageMounted(inputFile) - || !FileHelper.isStorageMounted(outputFile)) { - throw new PgpGeneralException( - getString(R.string.error_external_storage_not_ready)); - } - - inStream = new FileInputStream(inputFile); - File file = new File(inputFile); - inLength = file.length(); - inputData = new InputData(inStream, inLength); - - outStream = new FileOutputStream(outputFile); - - break; - - // TODO: not used currently -// case TARGET_STREAM: /* Encrypting stream from content uri */ -// Uri providerUri = (Uri) data.getParcelable(ENCRYPT_PROVIDER_URI); -// -// // InputStream -// InputStream in = getContentResolver().openInputStream(providerUri); -// inLength = PgpHelper.getLengthOfStream(in); -// inputData = new InputData(in, inLength); -// -// // OutputStream -// try { -// while (true) { -// streamFilename = PgpHelper.generateRandomFilename(32); -// if (streamFilename == null) { -// throw new PgpGeneralException("couldn't generate random file name"); -// } -// openFileInput(streamFilename).close(); -// } -// } catch (FileNotFoundException e) { -// // found a name that isn't used yet -// } -// outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE); -// -// break; - - default: - throw new PgpGeneralException("No target choosen!"); - - } - - /* Operation */ - PgpSignEncrypt.Builder builder = - new PgpSignEncrypt.Builder(this, inputData, outStream); - builder.progress(this); - - builder.enableAsciiArmorOutput(useAsciiArmor) - .compressionId(compressionId) - .symmetricEncryptionAlgorithm( - Preferences.getPreferences(this).getDefaultEncryptionAlgorithm()) - .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures()) - .encryptionKeyIds(encryptionKeyIds) - .symmetricPassphrase(symmetricPassphrase) - .signatureKeyId(signatureKeyId) - .signatureHashAlgorithm( - Preferences.getPreferences(this).getDefaultHashAlgorithm()) - .signaturePassphrase( - PassphraseCacheService.getCachedPassphrase(this, signatureKeyId)); - - builder.build().execute(); - - outStream.close(); - - /* Output */ - - Bundle resultData = new Bundle(); - - switch (target) { - case TARGET_BYTES: - byte output[] = ((ByteArrayOutputStream) outStream).toByteArray(); - - resultData.putByteArray(RESULT_BYTES, output); - - break; - case TARGET_URI: - // nothing, file was written, just send okay - - break; -// case TARGET_STREAM: -// String uri = DataStream.buildDataStreamUri(streamFilename).toString(); -// resultData.putString(RESULT_URI, uri); -// -// break; - } - - OtherHelper.logDebugBundle(resultData, "resultData"); - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_DECRYPT_VERIFY.equals(action)) { - try { - /* Input */ - int target = data.getInt(TARGET); - - byte[] bytes = data.getByteArray(DECRYPT_CIPHERTEXT_BYTES); - String passphrase = data.getString(DECRYPT_PASSPHRASE); - - InputStream inStream; - long inLength; - InputData inputData; - OutputStream outStream; - String streamFilename = null; - switch (target) { - case TARGET_BYTES: /* decrypting bytes directly */ - inStream = new ByteArrayInputStream(bytes); - inLength = bytes.length; - - inputData = new InputData(inStream, inLength); - outStream = new ByteArrayOutputStream(); - - break; - - case TARGET_URI: /* decrypting file */ - String inputFile = data.getString(ENCRYPT_INPUT_FILE); - String outputFile = data.getString(ENCRYPT_OUTPUT_FILE); - - // check if storage is ready - if (!FileHelper.isStorageMounted(inputFile) - || !FileHelper.isStorageMounted(outputFile)) { - throw new PgpGeneralException( - getString(R.string.error_external_storage_not_ready)); - } - - // InputStream - inLength = -1; - inStream = new FileInputStream(inputFile); - File file = new File(inputFile); - inLength = file.length(); - inputData = new InputData(inStream, inLength); - - // OutputStream - outStream = new FileOutputStream(outputFile); - - break; - - // TODO: not used, maybe contains code useful for new decrypt method for files? -// case TARGET_STREAM: /* decrypting stream from content uri */ -// Uri providerUri = (Uri) data.getParcelable(ENCRYPT_PROVIDER_URI); -// -// // InputStream -// InputStream in = getContentResolver().openInputStream(providerUri); -// inLength = PgpHelper.getLengthOfStream(in); -// inputData = new InputData(in, inLength); -// -// // OutputStream -// try { -// while (true) { -// streamFilename = PgpHelper.generateRandomFilename(32); -// if (streamFilename == null) { -// throw new PgpGeneralException("couldn't generate random file name"); -// } -// openFileInput(streamFilename).close(); -// } -// } catch (FileNotFoundException e) { -// // found a name that isn't used yet -// } -// outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE); -// -// break; - - default: - throw new PgpGeneralException("No target choosen!"); - - } - - /* Operation */ - - Bundle resultData = new Bundle(); - - // verifyText and decrypt returning additional resultData values for the - // verification of signatures - PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream); - builder.progressDialogUpdater(this); - - builder.allowSymmetricDecryption(true) - .passphrase(passphrase); - - PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute(); - - outStream.close(); - - resultData.putParcelable(RESULT_DECRYPT_VERIFY_RESULT, decryptVerifyResult); - - /* Output */ - - switch (target) { - case TARGET_BYTES: - byte output[] = ((ByteArrayOutputStream) outStream).toByteArray(); - resultData.putByteArray(RESULT_DECRYPTED_BYTES, output); - break; - case TARGET_URI: - // nothing, file was written, just send okay and verification bundle - - break; -// case TARGET_STREAM: -// String uri = DataStream.buildDataStreamUri(streamFilename).toString(); -// resultData.putString(RESULT_URI, uri); -// -// break; - } - - OtherHelper.logDebugBundle(resultData, "resultData"); - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_SAVE_KEYRING.equals(action)) { - try { - /* Input */ - SaveKeyringParcel saveParams = data.getParcelable(SAVE_KEYRING_PARCEL); - String oldPassphrase = saveParams.oldPassphrase; - String newPassphrase = saveParams.newPassphrase; - boolean canSign = true; - - if (data.containsKey(SAVE_KEYRING_CAN_SIGN)) { - canSign = data.getBoolean(SAVE_KEYRING_CAN_SIGN); - } - - if (newPassphrase == null) { - newPassphrase = oldPassphrase; - } - - long masterKeyId = saveParams.keys.get(0).getKeyID(); - - /* Operation */ - if (!canSign) { - PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 50, 100)); - PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRing(this, masterKeyId); - keyRing = keyOperations.changeSecretKeyPassphrase(keyRing, - oldPassphrase, newPassphrase); - setProgress(R.string.progress_saving_key_ring, 50, 100); - ProviderHelper.saveKeyRing(this, keyRing); - setProgress(R.string.progress_done, 100, 100); - } else { - PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 90, 100)); - PGPSecretKeyRing privkey = ProviderHelper.getPGPSecretKeyRing(this, masterKeyId); - PGPPublicKeyRing pubkey = ProviderHelper.getPGPPublicKeyRing(this, masterKeyId); - PgpKeyOperation.Pair<PGPSecretKeyRing,PGPPublicKeyRing> pair = - keyOperations.buildSecretKey(privkey, pubkey, saveParams); - setProgress(R.string.progress_saving_key_ring, 90, 100); - // save the pair - ProviderHelper.saveKeyRing(this, pair.second, pair.first); - setProgress(R.string.progress_done, 100, 100); - } - PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase); - - /* Output */ - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_GENERATE_KEY.equals(action)) { - try { - /* Input */ - int algorithm = data.getInt(GENERATE_KEY_ALGORITHM); - String passphrase = data.getString(GENERATE_KEY_SYMMETRIC_PASSPHRASE); - int keysize = data.getInt(GENERATE_KEY_KEY_SIZE); - boolean masterKey = data.getBoolean(GENERATE_KEY_MASTER_KEY); - - /* Operation */ - PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100)); - PGPSecretKey newKey = keyOperations.createKey(algorithm, keysize, - passphrase, masterKey); - - /* Output */ - Bundle resultData = new Bundle(); - resultData.putByteArray(RESULT_NEW_KEY, - PgpConversionHelper.PGPSecretKeyToBytes(newKey)); - - OtherHelper.logDebugBundle(resultData, "resultData"); - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_GENERATE_DEFAULT_RSA_KEYS.equals(action)) { - // generate one RSA 4096 key for signing and one subkey for encrypting! - try { - /* Input */ - String passphrase = data.getString(GENERATE_KEY_SYMMETRIC_PASSPHRASE); - ArrayList<PGPSecretKey> newKeys = new ArrayList<PGPSecretKey>(); - ArrayList<Integer> keyUsageList = new ArrayList<Integer>(); - - /* Operation */ - int keysTotal = 3; - int keysCreated = 0; - setProgress( - getApplicationContext().getResources(). - getQuantityString(R.plurals.progress_generating, keysTotal), - keysCreated, - keysTotal); - PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100)); - - PGPSecretKey masterKey = keyOperations.createKey(Id.choice.algorithm.rsa, - 4096, passphrase, true); - newKeys.add(masterKey); - keyUsageList.add(KeyFlags.CERTIFY_OTHER); - keysCreated++; - setProgress(keysCreated, keysTotal); - - PGPSecretKey subKey = keyOperations.createKey(Id.choice.algorithm.rsa, - 4096, passphrase, false); - newKeys.add(subKey); - keyUsageList.add(KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE); - keysCreated++; - setProgress(keysCreated, keysTotal); - - subKey = keyOperations.createKey(Id.choice.algorithm.rsa, - 4096, passphrase, false); - newKeys.add(subKey); - keyUsageList.add(KeyFlags.SIGN_DATA); - keysCreated++; - setProgress(keysCreated, keysTotal); - - // TODO: default to one master for cert, one sub for encrypt and one sub - // for sign - - /* Output */ - - Bundle resultData = new Bundle(); - resultData.putByteArray(RESULT_NEW_KEY, - PgpConversionHelper.PGPSecretKeyArrayListToBytes(newKeys)); - resultData.putIntegerArrayList(RESULT_KEY_USAGES, keyUsageList); - - OtherHelper.logDebugBundle(resultData, "resultData"); - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_DELETE_FILE_SECURELY.equals(action)) { - try { - /* Input */ - String deleteFile = data.getString(DELETE_FILE); - - /* Operation */ - try { - PgpHelper.deleteFileSecurely(this, this, new File(deleteFile)); - } catch (FileNotFoundException e) { - throw new PgpGeneralException( - getString(R.string.error_file_not_found, deleteFile)); - } catch (IOException e) { - throw new PgpGeneralException(getString(R.string.error_file_delete_failed, - deleteFile)); - } - - /* Output */ - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_IMPORT_KEYRING.equals(action)) { - try { - List<ImportKeysListEntry> entries = data.getParcelableArrayList(IMPORT_KEY_LIST); - - Bundle resultData = new Bundle(); - - PgpImportExport pgpImportExport = new PgpImportExport(this, this); - resultData = pgpImportExport.importKeyRings(entries); - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_EXPORT_KEYRING.equals(action)) { - try { - - boolean exportSecret = data.getBoolean(EXPORT_SECRET, false); - long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID); - String outputFile = data.getString(EXPORT_FILENAME); - - // If not exporting all keys get the masterKeyIds of the keys to export from the intent - boolean exportAll = data.getBoolean(EXPORT_ALL); - - // check if storage is ready - if (!FileHelper.isStorageMounted(outputFile)) { - throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready)); - } - - ArrayList<Long> publicMasterKeyIds = new ArrayList<Long>(); - ArrayList<Long> secretMasterKeyIds = new ArrayList<Long>(); - - String selection = null; - if(!exportAll) { - selection = KeychainDatabase.Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + " IN( "; - for(long l : masterKeyIds) { - selection += Long.toString(l) + ","; - } - selection = selection.substring(0, selection.length()-1) + " )"; - } - - Cursor cursor = getContentResolver().query(KeyRings.buildUnifiedKeyRingsUri(), - new String[]{ KeyRings.MASTER_KEY_ID, KeyRings.HAS_SECRET }, - selection, null, null); - try { - cursor.moveToFirst(); - do { - // export public either way - publicMasterKeyIds.add(cursor.getLong(0)); - // add secret if available (and requested) - if(exportSecret && cursor.getInt(1) != 0) - secretMasterKeyIds.add(cursor.getLong(0)); - } while(cursor.moveToNext()); - } finally { - cursor.close(); - } - - PgpImportExport pgpImportExport = new PgpImportExport(this, this, this); - Bundle resultData = pgpImportExport - .exportKeyRings(publicMasterKeyIds, secretMasterKeyIds, - new FileOutputStream(outputFile)); - - if (mIsCanceled) { - boolean isDeleted = new File(outputFile).delete(); - } - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_UPLOAD_KEYRING.equals(action)) { - try { - - /* Input */ - String keyServer = data.getString(UPLOAD_KEY_SERVER); - // and dataUri! - - /* Operation */ - HkpKeyServer server = new HkpKeyServer(keyServer); - - PGPPublicKeyRing keyring = (PGPPublicKeyRing) ProviderHelper.getPGPKeyRing(this, dataUri); - if (keyring != null) { - PgpImportExport pgpImportExport = new PgpImportExport(this, null); - - boolean uploaded = pgpImportExport.uploadKeyRingToServer(server, - (PGPPublicKeyRing) keyring); - if (!uploaded) { - throw new PgpGeneralException("Unable to export key to selected server"); - } - } - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_DOWNLOAD_AND_IMPORT_KEYS.equals(action)) { - try { - ArrayList<ImportKeysListEntry> entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST); - String keyServer = data.getString(DOWNLOAD_KEY_SERVER); - - // this downloads the keys and places them into the ImportKeysListEntry entries - HkpKeyServer server = new HkpKeyServer(keyServer); - - for (ImportKeysListEntry entry : entries) { - // if available use complete fingerprint for get request - byte[] downloadedKeyBytes; - if (entry.getFingerPrintHex() != null) { - downloadedKeyBytes = server.get("0x" + entry.getFingerPrintHex()).getBytes(); - } else { - downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes(); - } - - // create PGPKeyRing object based on downloaded armored key - PGPKeyRing downloadedKey = null; - BufferedInputStream bufferedInput = - new BufferedInputStream(new ByteArrayInputStream(downloadedKeyBytes)); - if (bufferedInput.available() > 0) { - InputStream in = PGPUtil.getDecoderStream(bufferedInput); - PGPObjectFactory objectFactory = new PGPObjectFactory(in); - - // get first object in block - Object obj; - if ((obj = objectFactory.nextObject()) != null) { - Log.d(Constants.TAG, "Found class: " + obj.getClass()); - - if (obj instanceof PGPKeyRing) { - downloadedKey = (PGPKeyRing) obj; - } else { - throw new PgpGeneralException("Object not recognized as PGPKeyRing!"); - } - } - } - - // verify downloaded key by comparing fingerprints - if (entry.getFingerPrintHex() != null) { - String downloadedKeyFp = PgpKeyHelper.convertFingerprintToHex( - downloadedKey.getPublicKey().getFingerprint()); - if (downloadedKeyFp.equals(entry.getFingerPrintHex())) { - Log.d(Constants.TAG, "fingerprint of downloaded key is the same as " + - "the requested fingerprint!"); - } else { - throw new PgpGeneralException("fingerprint of downloaded key is " + - "NOT the same as the requested fingerprint!"); - } - } - - // save key bytes in entry object for doing the - // actual import afterwards - entry.setBytes(downloadedKey.getEncoded()); - } - - - Intent importIntent = new Intent(this, KeychainIntentService.class); - importIntent.setAction(ACTION_IMPORT_KEYRING); - Bundle importData = new Bundle(); - importData.putParcelableArrayList(IMPORT_KEY_LIST, entries); - importIntent.putExtra(EXTRA_DATA, importData); - importIntent.putExtra(EXTRA_MESSENGER, mMessenger); - - // now import it with this service - onHandleIntent(importIntent); - - // result is handled in ACTION_IMPORT_KEYRING - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_CERTIFY_KEYRING.equals(action)) { - try { - - /* Input */ - long masterKeyId = data.getLong(CERTIFY_KEY_MASTER_KEY_ID); - long pubKeyId = data.getLong(CERTIFY_KEY_PUB_KEY_ID); - ArrayList<String> userIds = data.getStringArrayList(CERTIFY_KEY_UIDS); - - /* Operation */ - String signaturePassphrase = PassphraseCacheService.getCachedPassphrase(this, - masterKeyId); - if (signaturePassphrase == null) { - throw new PgpGeneralException("Unable to obtain passphrase"); - } - - PgpKeyOperation keyOperation = new PgpKeyOperation(new ProgressScaler(this, 0, 100, 100)); - PGPPublicKeyRing publicRing = ProviderHelper.getPGPPublicKeyRing(this, pubKeyId); - PGPPublicKey publicKey = publicRing.getPublicKey(pubKeyId); - PGPSecretKey certificationKey = PgpKeyHelper.getCertificationKey(this, - masterKeyId); - publicKey = keyOperation.certifyKey(certificationKey, publicKey, - userIds, signaturePassphrase); - publicRing = PGPPublicKeyRing.insertPublicKey(publicRing, publicKey); - - // store the signed key in our local cache - PgpImportExport pgpImportExport = new PgpImportExport(this, null); - int retval = pgpImportExport.storeKeyRingInCache(publicRing); - if (retval != Id.return_value.ok && retval != Id.return_value.updated) { - throw new PgpGeneralException("Failed to store signed key in local cache"); - } - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); - } catch (Exception e) { - sendErrorToHandler(e); - } - } - } - - private void sendErrorToHandler(Exception e) { - // Service was canceled. Do not send error to handler. - if (this.mIsCanceled) { - return; - } - // contextualize the exception, if necessary - if (e instanceof PgpGeneralMsgIdException) { - e = ((PgpGeneralMsgIdException) e).getContextualized(this); - } - Log.e(Constants.TAG, "ApgService Exception: ", e); - e.printStackTrace(); - - Bundle data = new Bundle(); - data.putString(KeychainIntentServiceHandler.DATA_ERROR, e.getMessage()); - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_EXCEPTION, null, data); - } - - private void sendMessageToHandler(Integer arg1, Integer arg2, Bundle data) { - // Service was canceled. Do not send message to handler. - if (this.mIsCanceled) { - return; - } - Message msg = Message.obtain(); - msg.arg1 = arg1; - if (arg2 != null) { - msg.arg2 = arg2; - } - 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); - } - } - - private void sendMessageToHandler(Integer arg1, Bundle data) { - sendMessageToHandler(arg1, null, data); - } - - private void sendMessageToHandler(Integer arg1) { - sendMessageToHandler(arg1, null, null); - } - - /** - * Set progressDialogUpdater of ProgressDialog by sending message to handler on UI thread - */ - public void setProgress(String message, int progress, int max) { - Log.d(Constants.TAG, "Send message by setProgress with progressDialogUpdater=" + progress + ", max=" - + max); - - Bundle data = new Bundle(); - if (message != null) { - data.putString(KeychainIntentServiceHandler.DATA_MESSAGE, message); - } - data.putInt(KeychainIntentServiceHandler.DATA_PROGRESS, progress); - data.putInt(KeychainIntentServiceHandler.DATA_PROGRESS_MAX, max); - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_UPDATE_PROGRESS, null, data); - } - - public void setProgress(int resourceId, int progress, int max) { - setProgress(getString(resourceId), progress, max); - } - - public void setProgress(int progress, int max) { - setProgress(null, progress, max); - } - - @Override - public boolean hasServiceStopped() { - return mIsCanceled; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java deleted file mode 100644 index 92d012c80..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.service; - -import android.app.Activity; -import android.content.DialogInterface.OnCancelListener; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager; -import android.widget.Toast; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; - -public class KeychainIntentServiceHandler extends Handler { - - // possible messages send from this service to handler on ui - public static final int MESSAGE_OKAY = 1; - public static final int MESSAGE_EXCEPTION = 2; - public static final int MESSAGE_UPDATE_PROGRESS = 3; - - // possible data keys for messages - public static final String DATA_ERROR = "error"; - public static final String DATA_PROGRESS = "progress"; - public static final String DATA_PROGRESS_MAX = "max"; - public static final String DATA_MESSAGE = "message"; - public static final String DATA_MESSAGE_ID = "message_id"; - - Activity mActivity; - ProgressDialogFragment mProgressDialogFragment; - - public KeychainIntentServiceHandler(Activity activity) { - this.mActivity = activity; - } - - public KeychainIntentServiceHandler(Activity activity, - ProgressDialogFragment progressDialogFragment) { - this.mActivity = activity; - this.mProgressDialogFragment = progressDialogFragment; - } - - public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage, - int progressDialogStyle) { - this(activity, progressDialogMessage, progressDialogStyle, false, null); - } - - public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage, - int progressDialogStyle, boolean cancelable, - OnCancelListener onCancelListener) { - this.mActivity = activity; - this.mProgressDialogFragment = ProgressDialogFragment.newInstance( - progressDialogMessage, - progressDialogStyle, - cancelable, - onCancelListener); - } - - public void showProgressDialog(FragmentActivity activity) { - // TODO: This is a hack!, see - // http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult - final FragmentManager manager = activity.getSupportFragmentManager(); - Handler handler = new Handler(); - handler.post(new Runnable() { - public void run() { - mProgressDialogFragment.show(manager, "progressDialog"); - } - }); - } - - @Override - public void handleMessage(Message message) { - Bundle data = message.getData(); - - switch (message.arg1) { - case MESSAGE_OKAY: - mProgressDialogFragment.dismissAllowingStateLoss(); - - break; - - case MESSAGE_EXCEPTION: - mProgressDialogFragment.dismissAllowingStateLoss(); - - // show error from service - if (data.containsKey(DATA_ERROR)) { - Toast.makeText(mActivity, - mActivity.getString(R.string.error_message, data.getString(DATA_ERROR)), - Toast.LENGTH_SHORT).show(); - } - - break; - - case MESSAGE_UPDATE_PROGRESS: - if (data.containsKey(DATA_PROGRESS) && data.containsKey(DATA_PROGRESS_MAX)) { - - // update progress from service - if (data.containsKey(DATA_MESSAGE)) { - mProgressDialogFragment.setProgress(data.getString(DATA_MESSAGE), - data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX)); - } else if (data.containsKey(DATA_MESSAGE_ID)) { - mProgressDialogFragment.setProgress(data.getInt(DATA_MESSAGE_ID), - data.getInt(DATA_PROGRESS), data.getInt(DATA_PROGRESS_MAX)); - } else { - mProgressDialogFragment.setProgress(data.getInt(DATA_PROGRESS), - data.getInt(DATA_PROGRESS_MAX)); - } - } - - break; - - default: - break; - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java deleted file mode 100644 index 962b304c7..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.service; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Binder; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.support.v4.util.LongSparseArray; -import android.util.Log; - -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; - -import java.util.Date; -import java.util.Iterator; - -/** - * This service runs in its own process, but is available to all other processes as the main - * passphrase cache. Use the static methods addCachedPassphrase and getCachedPassphrase for - * 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"; - public static final String ACTION_PASSPHRASE_CACHE_GET = Constants.INTENT_PREFIX - + "PASSPHRASE_CACHE_GET"; - - public static final String BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE = Constants.INTENT_PREFIX - + "PASSPHRASE_CACHE_BROADCAST"; - - public static final String EXTRA_TTL = "ttl"; - public static final String EXTRA_KEY_ID = "key_id"; - public static final String EXTRA_PASSPHRASE = "passphrase"; - public static final String EXTRA_MESSENGER = "messenger"; - - private static final int REQUEST_ID = 0; - private static final long DEFAULT_TTL = 15; - - private BroadcastReceiver mIntentReceiver; - - private LongSparseArray<String> mPassphraseCache = new LongSparseArray<String>(); - - Context mContext; - - /** - * This caches a new passphrase in memory by sending a new command to the service. An android - * service is only run once. Thus, when the service is already started, new commands just add - * new events to the alarm manager for new passphrases to let them timeout in the future. - * - * @param context - * @param keyId - * @param passphrase - */ - public static void addCachedPassphrase(Context context, long keyId, String passphrase) { - Log.d(TAG, "cacheNewPassphrase() for " + keyId); - - Intent intent = new Intent(context, PassphraseCacheService.class); - intent.setAction(ACTION_PASSPHRASE_CACHE_ADD); - intent.putExtra(EXTRA_TTL, Preferences.getPreferences(context).getPassphraseCacheTtl()); - intent.putExtra(EXTRA_PASSPHRASE, passphrase); - intent.putExtra(EXTRA_KEY_ID, keyId); - - context.startService(intent); - } - - /** - * Gets a cached passphrase from memory by sending an intent to the service. This method is - * designed to wait until the service returns the passphrase. - * - * @param context - * @param keyId - * @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); - - Intent intent = new Intent(context, PassphraseCacheService.class); - intent.setAction(ACTION_PASSPHRASE_CACHE_GET); - - final Object mutex = new Object(); - final Bundle returnBundle = new Bundle(); - - HandlerThread handlerThread = new HandlerThread("getPassphraseThread"); - handlerThread.start(); - Handler returnHandler = new Handler(handlerThread.getLooper()) { - @Override - public void handleMessage(Message message) { - if (message.obj != null) { - String passphrase = ((Bundle) message.obj).getString(EXTRA_PASSPHRASE); - returnBundle.putString(EXTRA_PASSPHRASE, passphrase); - } - synchronized (mutex) { - mutex.notify(); - } - // quit handlerThread - getLooper().quit(); - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - intent.putExtra(EXTRA_KEY_ID, keyId); - intent.putExtra(EXTRA_MESSENGER, messenger); - // send intent to this service - context.startService(intent); - - // Wait on mutex until passphrase is returned to handlerThread - synchronized (mutex) { - try { - mutex.wait(3000); - } catch (InterruptedException e) { - } - } - - if (returnBundle.containsKey(EXTRA_PASSPHRASE)) { - return returnBundle.getString(EXTRA_PASSPHRASE); - } else { - return null; - } - } - - /** - * Internal implementation to get cached passphrase. - * - * @param keyId - * @return - */ - private String getCachedPassphraseImpl(long keyId) { - Log.d(TAG, "getCachedPassphraseImpl() get masterKeyId for " + keyId); - - // try to get master key id which is used as an identifier for cached passphrases - long masterKeyId = keyId; - if (masterKeyId != Id.key.symmetric) { - masterKeyId = ProviderHelper.getMasterKeyId(this, - KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId))); - // Failure - if(masterKeyId == 0) - return null; - } - Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + masterKeyId); - - // get cached passphrase - String cachedPassphrase = mPassphraseCache.get(masterKeyId); - if (cachedPassphrase == null) { - // if key has no passphrase -> cache and return empty passphrase - if (!hasPassphrase(this, masterKeyId)) { - Log.d(Constants.TAG, "Key has no passphrase! Caches and returns empty passphrase!"); - - addCachedPassphrase(this, masterKeyId, ""); - return ""; - } else { - return null; - } - } - // set it again to reset the cache life cycle - Log.d(TAG, "Cache passphrase again when getting it!"); - addCachedPassphrase(this, masterKeyId, cachedPassphrase); - - return cachedPassphrase; - } - - /** - * Checks if key has a passphrase. - * - * @param secretKeyId - * @return true if it has a passphrase - */ - public static boolean hasPassphrase(Context context, long secretKeyId) { - // check if the key has no passphrase - try { - PGPSecretKeyRing secRing = ProviderHelper.getPGPSecretKeyRing(context, secretKeyId); - PGPSecretKey secretKey = null; - boolean foundValidKey = false; - for (Iterator keys = secRing.getSecretKeys(); keys.hasNext(); ) { - secretKey = (PGPSecretKey) keys.next(); - if (!secretKey.isPrivateKeyEmpty()) { - foundValidKey = true; - break; - } - } - - if (!foundValidKey) { - return false; - } - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - "SC").build("".toCharArray()); - PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor); - if (testKey != null) { - return false; - } - } catch (PGPException e) { - // silently catch - } - - return true; - } - - /** - * Register BroadcastReceiver that is unregistered when service is destroyed. This - * BroadcastReceiver hears on intents with ACTION_PASSPHRASE_CACHE_SERVICE to then timeout - * specific passphrases in memory. - */ - private void registerReceiver() { - if (mIntentReceiver == null) { - mIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - Log.d(TAG, "Received broadcast..."); - - if (action.equals(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE)) { - long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1); - timeout(context, keyId); - } - } - }; - - IntentFilter filter = new IntentFilter(); - filter.addAction(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE); - registerReceiver(mIntentReceiver, filter); - } - } - - /** - * Build pending intent that is executed by alarm manager to time out a specific passphrase - * - * @param context - * @param keyId - * @return - */ - private static PendingIntent buildIntent(Context context, long keyId) { - Intent intent = new Intent(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE); - intent.putExtra(EXTRA_KEY_ID, keyId); - PendingIntent sender = PendingIntent.getBroadcast(context, REQUEST_ID, intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - return sender; - } - - /** - * Executed when service is started by intent - */ - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(TAG, "onStartCommand()"); - - // register broadcastreceiver - registerReceiver(); - - if (intent != null && intent.getAction() != null) { - if (ACTION_PASSPHRASE_CACHE_ADD.equals(intent.getAction())) { - long ttl = intent.getLongExtra(EXTRA_TTL, DEFAULT_TTL); - 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: " - + keyId + ", ttl: " + ttl); - - // add keyId and passphrase to memory - mPassphraseCache.put(keyId, passphrase); - - if (ttl > 0) { - // register new alarm with keyId for this passphrase - long triggerTime = new Date().getTime() + (ttl * 1000); - AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE); - am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, keyId)); - } - } else if (ACTION_PASSPHRASE_CACHE_GET.equals(intent.getAction())) { - long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1); - Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER); - - String passphrase = getCachedPassphraseImpl(keyId); - - Message msg = Message.obtain(); - Bundle bundle = new Bundle(); - bundle.putString(EXTRA_PASSPHRASE, passphrase); - msg.obj = bundle; - try { - messenger.send(msg); - } catch (RemoteException e) { - Log.e(Constants.TAG, "Sending message failed", e); - } - } else { - Log.e(Constants.TAG, "Intent or Intent Action not supported!"); - } - } - - return START_STICKY; - } - - /** - * Called when one specific passphrase for keyId timed out - * - * @param context - * @param keyId - */ - private void timeout(Context context, long keyId) { - // remove passphrase corresponding to keyId from memory - mPassphraseCache.remove(keyId); - - Log.d(TAG, "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!"); - stopSelf(); - } - } - - @Override - public void onCreate() { - super.onCreate(); - mContext = this; - Log.d(Constants.TAG, "PassphraseCacheService, onCreate()"); - } - - @Override - public void onDestroy() { - super.onDestroy(); - Log.d(Constants.TAG, "PassphraseCacheService, onDestroy()"); - - unregisterReceiver(mIntentReceiver); - } - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - public class PassphraseCacheBinder extends Binder { - public PassphraseCacheService getService() { - return PassphraseCacheService.this; - } - } - - private final IBinder mBinder = new PassphraseCacheBinder(); - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java deleted file mode 100644 index 7c2dcf2c1..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2014 Ash Hughes <ashes-iontach@hotmail.com> - * - * 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 <http://www.gnu.org/licenses/>. - */ - - -package org.sufficientlysecure.keychain.service; - -import android.os.Parcel; -import android.os.Parcelable; - -import org.spongycastle.openpgp.PGPSecretKey; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; - -import java.util.ArrayList; -import java.util.GregorianCalendar; - -public class SaveKeyringParcel implements Parcelable { - - public ArrayList<String> userIDs; - public ArrayList<String> originalIDs; - public ArrayList<String> deletedIDs; - public boolean[] newIDs; - public boolean primaryIDChanged; - public boolean[] moddedKeys; - public ArrayList<PGPSecretKey> deletedKeys; - public ArrayList<GregorianCalendar> keysExpiryDates; - public ArrayList<Integer> keysUsages; - public String newPassphrase; - public String oldPassphrase; - public boolean[] newKeys; - public ArrayList<PGPSecretKey> keys; - public String originalPrimaryID; - - public SaveKeyringParcel() {} - - private SaveKeyringParcel(Parcel source) { - userIDs = (ArrayList<String>) source.readSerializable(); - originalIDs = (ArrayList<String>) source.readSerializable(); - deletedIDs = (ArrayList<String>) source.readSerializable(); - newIDs = source.createBooleanArray(); - primaryIDChanged = source.readByte() != 0; - moddedKeys = source.createBooleanArray(); - byte[] tmp = source.createByteArray(); - if (tmp == null) { - deletedKeys = null; - } else { - deletedKeys = PgpConversionHelper.BytesToPGPSecretKeyList(tmp); - } - keysExpiryDates = (ArrayList<GregorianCalendar>) source.readSerializable(); - keysUsages = source.readArrayList(Integer.class.getClassLoader()); - newPassphrase = source.readString(); - oldPassphrase = source.readString(); - newKeys = source.createBooleanArray(); - keys = PgpConversionHelper.BytesToPGPSecretKeyList(source.createByteArray()); - originalPrimaryID = source.readString(); - } - - @Override - public void writeToParcel(Parcel destination, int flags) { - destination.writeSerializable(userIDs); //might not be the best method to store. - destination.writeSerializable(originalIDs); - destination.writeSerializable(deletedIDs); - destination.writeBooleanArray(newIDs); - destination.writeByte((byte) (primaryIDChanged ? 1 : 0)); - destination.writeBooleanArray(moddedKeys); - byte[] tmp = null; - if (deletedKeys.size() != 0) { - tmp = PgpConversionHelper.PGPSecretKeyArrayListToBytes(deletedKeys); - } - destination.writeByteArray(tmp); - destination.writeSerializable(keysExpiryDates); - destination.writeList(keysUsages); - destination.writeString(newPassphrase); - destination.writeString(oldPassphrase); - destination.writeBooleanArray(newKeys); - destination.writeByteArray(PgpConversionHelper.PGPSecretKeyArrayListToBytes(keys)); - destination.writeString(originalPrimaryID); - } - - public static final Creator<SaveKeyringParcel> CREATOR = new Creator<SaveKeyringParcel>() { - public SaveKeyringParcel createFromParcel(final Parcel source) { - return new SaveKeyringParcel(source); - } - - public SaveKeyringParcel[] newArray(final int size) { - return new SaveKeyringParcel[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java deleted file mode 100644 index 7027c114e..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2011 Senecaso - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.ProgressDialog; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ArrayAdapter; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.ListView; -import android.widget.Spinner; -import android.widget.TextView; -import android.widget.Toast; -import com.beardedhen.androidbootstrap.BootstrapButton; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter; -import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; - -/** - * Signs the specified public key with the specified secret master key - */ -public class CertifyKeyActivity extends ActionBarActivity implements - SelectSecretKeyLayoutFragment.SelectSecretKeyCallback, LoaderManager.LoaderCallbacks<Cursor> { - private BootstrapButton mSignButton; - private CheckBox mUploadKeyCheckbox; - private Spinner mSelectKeyserverSpinner; - - private SelectSecretKeyLayoutFragment mSelectKeyFragment; - - private Uri mDataUri; - private long mPubKeyId = 0; - private long mMasterKeyId = 0; - - private ListView mUserIds; - private ViewKeyUserIdsAdapter mUserIdsAdapter; - - private static final int LOADER_ID_KEYRING = 0; - private static final int LOADER_ID_USER_IDS = 1; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.certify_key_activity); - - final ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(false); - actionBar.setHomeButtonEnabled(false); - - mSelectKeyFragment = (SelectSecretKeyLayoutFragment) getSupportFragmentManager() - .findFragmentById(R.id.sign_key_select_key_fragment); - mSelectKeyFragment.setCallback(this); - mSelectKeyFragment.setFilterCertify(true); - - mSelectKeyserverSpinner = (Spinner) findViewById(R.id.sign_key_keyserver); - ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, - android.R.layout.simple_spinner_item, Preferences.getPreferences(this) - .getKeyServers()); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mSelectKeyserverSpinner.setAdapter(adapter); - - mUploadKeyCheckbox = (CheckBox) findViewById(R.id.sign_key_upload_checkbox); - if (!mUploadKeyCheckbox.isChecked()) { - mSelectKeyserverSpinner.setEnabled(false); - } else { - mSelectKeyserverSpinner.setEnabled(true); - } - - mUploadKeyCheckbox.setOnCheckedChangeListener(new OnCheckedChangeListener() { - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (!isChecked) { - mSelectKeyserverSpinner.setEnabled(false); - } else { - mSelectKeyserverSpinner.setEnabled(true); - } - } - }); - - mSignButton = (BootstrapButton) findViewById(R.id.sign_key_sign_button); - mSignButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - if (mPubKeyId != 0) { - if (mMasterKeyId == 0) { - mSelectKeyFragment.setError(getString(R.string.select_key_to_sign)); - } else { - initiateSigning(); - } - } - } - }); - - mDataUri = getIntent().getData(); - if (mDataUri == null) { - Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!"); - finish(); - return; - } - Log.e(Constants.TAG, "uri: " + mDataUri); - - mUserIds = (ListView) findViewById(R.id.user_ids); - - mUserIdsAdapter = new ViewKeyUserIdsAdapter(this, null, 0, true); - mUserIds.setAdapter(mUserIdsAdapter); - mUserIds.setOnItemClickListener(mUserIdsAdapter); - - getSupportLoaderManager().initLoader(LOADER_ID_KEYRING, null, this); - getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); - - } - - static final String USER_IDS_SELECTION = UserIds.IS_REVOKED + " = 0"; - - static final String[] KEYRING_PROJECTION = - new String[] { - KeyRings._ID, - KeyRings.MASTER_KEY_ID, - KeyRings.FINGERPRINT, - KeyRings.USER_ID, - }; - static final int INDEX_MASTER_KEY_ID = 1; - static final int INDEX_FINGERPRINT = 2; - static final int INDEX_USER_ID = 3; - - @Override - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - switch(id) { - case LOADER_ID_KEYRING: { - Uri uri = KeyRings.buildUnifiedKeyRingUri(mDataUri); - return new CursorLoader(this, uri, KEYRING_PROJECTION, null, null, null); - } - case LOADER_ID_USER_IDS: { - Uri uri = UserIds.buildUserIdsUri(mDataUri); - return new CursorLoader(this, uri, - ViewKeyUserIdsAdapter.USER_IDS_PROJECTION, USER_IDS_SELECTION, null, null); - } - } - return null; - } - - @Override - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - switch(loader.getId()) { - case LOADER_ID_KEYRING: - // the first key here is our master key - if (data.moveToFirst()) { - // TODO: put findViewById in onCreate! - mPubKeyId = data.getLong(INDEX_MASTER_KEY_ID); - String keyIdStr = PgpKeyHelper.convertKeyIdToHexShort(mPubKeyId); - ((TextView) findViewById(R.id.key_id)).setText(keyIdStr); - - String mainUserId = data.getString(INDEX_USER_ID); - ((TextView) findViewById(R.id.main_user_id)).setText(mainUserId); - - byte[] fingerprintBlob = data.getBlob(INDEX_FINGERPRINT); - String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob); - ((TextView) findViewById(R.id.fingerprint)) - .setText(PgpKeyHelper.colorizeFingerprint(fingerprint)); - } - break; - case LOADER_ID_USER_IDS: - mUserIdsAdapter.swapCursor(data); - break; - } - } - - @Override - public void onLoaderReset(Loader<Cursor> loader) { - switch(loader.getId()) { - case LOADER_ID_USER_IDS: - mUserIdsAdapter.swapCursor(null); - break; - } - } - - /** - * handles the UI bits of the signing process on the UI thread - */ - private void initiateSigning() { - PGPPublicKeyRing pubring = ProviderHelper.getPGPPublicKeyRing(this, mPubKeyId); - if (pubring != null) { - // if we have already signed this key, dont bother doing it again - boolean alreadySigned = false; - - /* todo: reconsider this at a later point when certs are in the db - @SuppressWarnings("unchecked") - Iterator<PGPSignature> itr = pubring.getPublicKey(mPubKeyId).getSignatures(); - while (itr.hasNext()) { - PGPSignature sig = itr.next(); - if (sig.getKeyID() == mMasterKeyId) { - alreadySigned = true; - break; - } - } - */ - - if (!alreadySigned) { - /* - * get the user's passphrase for this key (if required) - */ - String passphrase = PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId); - if (passphrase == null) { - PassphraseDialogFragment.show(this, mMasterKeyId, - new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - startSigning(); - } - } - }); - // bail out; need to wait until the user has entered the passphrase before trying again - return; - } else { - startSigning(); - } - } else { - Toast.makeText(this, R.string.key_has_already_been_signed, Toast.LENGTH_SHORT) - .show(); - - setResult(RESULT_CANCELED); - finish(); - } - } - } - - /** - * kicks off the actual signing process on a background thread - */ - private void startSigning() { - - // Bail out if there is not at least one user id selected - ArrayList<String> userIds = mUserIdsAdapter.getSelectedUserIds(); - if (userIds.isEmpty()) { - Toast.makeText(CertifyKeyActivity.this, "No User IDs to sign selected!", - Toast.LENGTH_SHORT).show(); - return; - } - - // Send all information needed to service to sign key in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_CERTIFY_KEYRING); - - // fill values for this action - Bundle data = new Bundle(); - - data.putLong(KeychainIntentService.CERTIFY_KEY_MASTER_KEY_ID, mMasterKeyId); - data.putLong(KeychainIntentService.CERTIFY_KEY_PUB_KEY_ID, mPubKeyId); - data.putStringArrayList(KeychainIntentService.CERTIFY_KEY_UIDS, userIds); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after signing is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, - getString(R.string.progress_signing), ProgressDialog.STYLE_SPINNER) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - - Toast.makeText(CertifyKeyActivity.this, R.string.key_sign_success, - Toast.LENGTH_SHORT).show(); - - // check if we need to send the key to the server or not - if (mUploadKeyCheckbox.isChecked()) { - // upload the newly signed key to the keyserver - uploadKey(); - } else { - setResult(RESULT_OK); - finish(); - } - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - saveHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } - - private void uploadKey() { - // Send all information needed to service to upload key in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_UPLOAD_KEYRING); - - // set data uri as path to keyring - intent.setData(mDataUri); - - // fill values for this action - Bundle data = new Bundle(); - - Spinner keyServer = (Spinner) findViewById(R.id.sign_key_keyserver); - String server = (String) keyServer.getSelectedItem(); - data.putString(KeychainIntentService.UPLOAD_KEY_SERVER, server); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after uploading is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, - getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - Toast.makeText(CertifyKeyActivity.this, R.string.key_send_success, - Toast.LENGTH_SHORT).show(); - - setResult(RESULT_OK); - finish(); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - saveHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } - - /** - * callback from select key fragment - */ - @Override - public void onKeySelected(long secretKeyId) { - mMasterKeyId = secretKeyId; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java deleted file mode 100644 index 8533e9072..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.view.PagerTabStrip; -import android.support.v4.view.ViewPager; -import android.widget.Toast; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.helper.FileHelper; -import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.regex.Matcher; - -public class DecryptActivity extends DrawerActivity { - - /* Intents */ - public static final String ACTION_DECRYPT = Constants.INTENT_PREFIX + "DECRYPT"; - - /* EXTRA keys for input */ - public static final String EXTRA_TEXT = "text"; - - ViewPager mViewPager; - PagerTabStrip mPagerTabStrip; - PagerTabStripAdapter mTabsAdapter; - - Bundle mMessageFragmentBundle = new Bundle(); - Bundle mFileFragmentBundle = new Bundle(); - int mSwitchToTab = PAGER_TAB_MESSAGE; - - private static final int PAGER_TAB_MESSAGE = 0; - private static final int PAGER_TAB_FILE = 1; - - private void initView() { - mViewPager = (ViewPager) findViewById(R.id.decrypt_pager); - mPagerTabStrip = (PagerTabStrip) findViewById(R.id.decrypt_pager_tab_strip); - - mTabsAdapter = new PagerTabStripAdapter(this); - mViewPager.setAdapter(mTabsAdapter); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.decrypt_activity); - - // set actionbar without home button if called from another app - ActionBarHelper.setBackButton(this); - - initView(); - - setupDrawerNavigation(savedInstanceState); - - // Handle intent actions, maybe changes the bundles - handleActions(getIntent()); - - mTabsAdapter.addTab(DecryptMessageFragment.class, - mMessageFragmentBundle, getString(R.string.label_message)); - mTabsAdapter.addTab(DecryptFileFragment.class, - mFileFragmentBundle, getString(R.string.label_file)); - mViewPager.setCurrentItem(mSwitchToTab); - } - - - /** - * Handles all actions with this intent - * - * @param intent - */ - private void handleActions(Intent intent) { - String action = intent.getAction(); - Bundle extras = intent.getExtras(); - String type = intent.getType(); - Uri uri = intent.getData(); - - if (extras == null) { - extras = new Bundle(); - } - - /* - * Android's Action - */ - if (Intent.ACTION_SEND.equals(action) && type != null) { - // When sending to Keychain Decrypt via share menu - if ("text/plain".equals(type)) { - // Plain text - String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); - if (sharedText != null) { - // handle like normal text decryption, override action and extras to later - // executeServiceMethod ACTION_DECRYPT in main actions - extras.putString(EXTRA_TEXT, sharedText); - action = ACTION_DECRYPT; - } - } else { - // Binary via content provider (could also be files) - // override uri to get stream from send - uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); - action = ACTION_DECRYPT; - } - } else if (Intent.ACTION_VIEW.equals(action)) { - // Android's Action when opening file associated to Keychain (see AndroidManifest.xml) - - // override action - action = ACTION_DECRYPT; - } - - String textData = extras.getString(EXTRA_TEXT); - - /** - * Main Actions - */ - if (ACTION_DECRYPT.equals(action) && textData != null) { - Log.d(Constants.TAG, "textData not null, matching text ..."); - Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(textData); - if (matcher.matches()) { - Log.d(Constants.TAG, "PGP_MESSAGE matched"); - textData = matcher.group(1); - // replace non breakable spaces - textData = textData.replaceAll("\\xa0", " "); - - mMessageFragmentBundle.putString(DecryptMessageFragment.ARG_CIPHERTEXT, textData); - mSwitchToTab = PAGER_TAB_MESSAGE; - } else { - matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(textData); - if (matcher.matches()) { - Log.d(Constants.TAG, "PGP_CLEARTEXT_SIGNATURE matched"); - textData = matcher.group(1); - // replace non breakable spaces - textData = textData.replaceAll("\\xa0", " "); - - mMessageFragmentBundle.putString(DecryptMessageFragment.ARG_CIPHERTEXT, textData); - mSwitchToTab = PAGER_TAB_MESSAGE; - } else { - Log.d(Constants.TAG, "Nothing matched!"); - } - } - } else if (ACTION_DECRYPT.equals(action) && uri != null) { - // get file path from uri - String path = FileHelper.getPath(this, uri); - - if (path != null) { - mFileFragmentBundle.putString(DecryptFileFragment.ARG_FILENAME, path); - mSwitchToTab = PAGER_TAB_FILE; - } else { - Log.e(Constants.TAG, - "Direct binary data without actual file in filesystem is not supported. " + - "Please use the Remote Service API!"); - Toast.makeText(this, R.string.error_only_files_are_supported, Toast.LENGTH_LONG) - .show(); - // end activity - finish(); - } - } else { - Log.e(Constants.TAG, - "Include the extra 'text' or an Uri with setData() in your Intent!"); - } - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java deleted file mode 100644 index 492c0cf29..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFileFragment.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.app.ProgressDialog; -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.ViewGroup; -import android.widget.CheckBox; -import android.widget.EditText; - -import com.beardedhen.androidbootstrap.BootstrapButton; -import com.devspark.appmsg.AppMsg; - -import org.openintents.openpgp.OpenPgpSignatureResult; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.FileHelper; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.File; - -public class DecryptFileFragment extends DecryptFragment { - public static final String ARG_FILENAME = "filename"; - - private static final int RESULT_CODE_FILE = 0x00007003; - - // view - private EditText mFilename; - private CheckBox mDeleteAfter; - private BootstrapButton mBrowse; - private BootstrapButton mDecryptButton; - - private String mInputFilename = null; - private String mOutputFilename = null; - - private FileDialogFragment mFileDialog; - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.decrypt_file_fragment, container, false); - - mFilename = (EditText) view.findViewById(R.id.decrypt_file_filename); - mBrowse = (BootstrapButton) view.findViewById(R.id.decrypt_file_browse); - mDeleteAfter = (CheckBox) view.findViewById(R.id.decrypt_file_delete_after_decryption); - mDecryptButton = (BootstrapButton) view.findViewById(R.id.decrypt_file_action_decrypt); - mBrowse.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - FileHelper.openFile(DecryptFileFragment.this, mFilename.getText().toString(), "*/*", - RESULT_CODE_FILE); - } - }); - mDecryptButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - decryptAction(); - } - }); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - String filename = getArguments().getString(ARG_FILENAME); - if (filename != null) { - mFilename.setText(filename); - } - } - - private void guessOutputFilename() { - mInputFilename = mFilename.getText().toString(); - File file = new File(mInputFilename); - String filename = file.getName(); - if (filename.endsWith(".asc") || filename.endsWith(".gpg") || filename.endsWith(".pgp")) { - filename = filename.substring(0, filename.length() - 4); - } - mOutputFilename = Constants.Path.APP_DIR + "/" + filename; - } - - private void decryptAction() { - String currentFilename = mFilename.getText().toString(); - if (mInputFilename == null || !mInputFilename.equals(currentFilename)) { - guessOutputFilename(); - } - - if (mInputFilename.equals("")) { - AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show(); - return; - } - - if (mInputFilename.startsWith("file")) { - File file = new File(mInputFilename); - if (!file.exists() || !file.isFile()) { - AppMsg.makeText( - getActivity(), - getString(R.string.error_message, - getString(R.string.error_file_not_found)), AppMsg.STYLE_ALERT) - .show(); - return; - } - } - - askForOutputFilename(); - } - - private void askForOutputFilename() { - // Message is received after passphrase is cached - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == FileDialogFragment.MESSAGE_OKAY) { - Bundle data = message.getData(); - mOutputFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); - decryptStart(null); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - mFileDialog = FileDialogFragment.newInstance(messenger, - getString(R.string.title_decrypt_to_file), - getString(R.string.specify_file_to_decrypt_to), mOutputFilename, null); - - mFileDialog.show(getActivity().getSupportFragmentManager(), "fileDialog"); - } - - @Override - protected void decryptStart(String passphrase) { - Log.d(Constants.TAG, "decryptStart"); - - // Send all information needed to service to decrypt in other thread - Intent intent = new Intent(getActivity(), KeychainIntentService.class); - - // fill values for this action - Bundle data = new Bundle(); - - intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY); - - // data - data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_URI); - - Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename=" - + mOutputFilename); - - data.putString(KeychainIntentService.ENCRYPT_INPUT_FILE, mInputFilename); - data.putString(KeychainIntentService.ENCRYPT_OUTPUT_FILE, mOutputFilename); - - data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after encrypting is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), - getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get returned data bundle - Bundle returnData = message.getData(); - - PgpDecryptVerifyResult decryptVerifyResult = - returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT); - - if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) { - showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded()); - } else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == - decryptVerifyResult.getStatus()) { - showPassphraseDialog(Id.key.symmetric); - } else { - AppMsg.makeText(getActivity(), R.string.decryption_successful, - AppMsg.STYLE_INFO).show(); - - if (mDeleteAfter.isChecked()) { - // Create and show dialog to delete original file - DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment - .newInstance(mInputFilename); - deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog"); - } - - OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult(); - - // display signature result in activity - onSignatureResult(signatureResult); - } - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - saveHandler.showProgressDialog(getActivity()); - - // start service with intent - getActivity().startService(intent); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case RESULT_CODE_FILE: { - if (resultCode == Activity.RESULT_OK && data != null) { - try { - String path = FileHelper.getPath(getActivity(), data.getData()); - Log.d(Constants.TAG, "path=" + path); - - mFilename.setText(path); - } catch (NullPointerException e) { - Log.e(Constants.TAG, "Nullpointer while retrieving path!"); - } - } - return; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - - break; - } - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java deleted file mode 100644 index 1c465f55c..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.support.v4.app.Fragment; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; -import com.devspark.appmsg.AppMsg; - -import org.openintents.openpgp.OpenPgpSignatureResult; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; - -public class DecryptFragment extends Fragment { - private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006; - - protected long mSignatureKeyId = 0; - - protected RelativeLayout mSignatureLayout = null; - protected ImageView mSignatureStatusImage = null; - protected TextView mUserId = null; - protected TextView mUserIdRest = null; - - protected BootstrapButton mLookupKey = null; - - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mSignatureLayout = (RelativeLayout) getView().findViewById(R.id.signature); - mSignatureStatusImage = (ImageView) getView().findViewById(R.id.ic_signature_status); - mUserId = (TextView) getView().findViewById(R.id.mainUserId); - mUserIdRest = (TextView) getView().findViewById(R.id.mainUserIdRest); - mLookupKey = (BootstrapButton) getView().findViewById(R.id.lookup_key); - mLookupKey.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - lookupUnknownKey(mSignatureKeyId); - } - }); - mSignatureLayout.setVisibility(View.GONE); - mSignatureLayout.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - lookupUnknownKey(mSignatureKeyId); - } - }); - } - - private void lookupUnknownKey(long unknownKeyId) { - Intent intent = new Intent(getActivity(), ImportKeysActivity.class); - intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER); - intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, unknownKeyId); - startActivityForResult(intent, RESULT_CODE_LOOKUP_KEY); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - - case RESULT_CODE_LOOKUP_KEY: { - if (resultCode == Activity.RESULT_OK) { - // TODO: generate new OpenPgpSignatureResult and display it - } - return; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - - break; - } - } - } - - protected void onSignatureResult(OpenPgpSignatureResult signatureResult) { - mSignatureKeyId = 0; - mSignatureLayout.setVisibility(View.GONE); - if (signatureResult != null) { - - mSignatureKeyId = signatureResult.getKeyId(); - - String userId = signatureResult.getUserId(); - String[] userIdSplit = PgpKeyHelper.splitUserId(userId); - if (userIdSplit[0] != null) { - mUserId.setText(userId); - } else { - mUserId.setText(R.string.user_id_no_name); - } - if (userIdSplit[1] != null) { - mUserIdRest.setText(userIdSplit[1]); - } else { - mUserIdRest.setText(getString(R.string.label_key_id) + ": " - + PgpKeyHelper.convertKeyIdToHex(mSignatureKeyId)); - } - - switch (signatureResult.getStatus()) { - case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: { - mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); - mLookupKey.setVisibility(View.GONE); - break; - } - - // TODO! -// case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: { -// break; -// } - - case OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY: { - mSignatureStatusImage.setImageResource(R.drawable.overlay_error); - mLookupKey.setVisibility(View.VISIBLE); - AppMsg.makeText(getActivity(), - R.string.unknown_signature, - AppMsg.STYLE_ALERT).show(); - break; - } - - default: { - mSignatureStatusImage.setImageResource(R.drawable.overlay_error); - mLookupKey.setVisibility(View.GONE); - break; - } - } - mSignatureLayout.setVisibility(View.VISIBLE); - } - } - - protected void showPassphraseDialog(long keyId) { - PassphraseDialogFragment.show(getActivity(), keyId, - new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - String passphrase = - message.getData().getString(PassphraseDialogFragment.MESSAGE_DATA_PASSPHRASE); - decryptStart(passphrase); - } - } - }); - } - - /** - * Should be overridden by MessageFragment and FileFragment to start actual decryption - * - * @param passphrase - */ - protected void decryptStart(String passphrase) { - - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java deleted file mode 100644 index 2169bbd77..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptMessageFragment.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -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.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.EditText; - -import com.beardedhen.androidbootstrap.BootstrapButton; -import com.devspark.appmsg.AppMsg; - -import org.openintents.openpgp.OpenPgpSignatureResult; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; -import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.regex.Matcher; - -public class DecryptMessageFragment extends DecryptFragment { - public static final String ARG_CIPHERTEXT = "ciphertext"; - - // view - private EditText mMessage; - private BootstrapButton mDecryptButton; - private BootstrapButton mDecryptFromCLipboardButton; - - // model - private String mCiphertext; - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.decrypt_message_fragment, container, false); - - mMessage = (EditText) view.findViewById(R.id.message); - mDecryptButton = (BootstrapButton) view.findViewById(R.id.action_decrypt); - mDecryptFromCLipboardButton = (BootstrapButton) view.findViewById(R.id.action_decrypt_from_clipboard); - mDecryptButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - decryptClicked(); - } - }); - mDecryptFromCLipboardButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - decryptFromClipboardClicked(); - } - }); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - String ciphertext = getArguments().getString(ARG_CIPHERTEXT); - if (ciphertext != null) { - mMessage.setText(ciphertext); - decryptStart(null); - } - } - - private void decryptClicked() { - mCiphertext = mMessage.getText().toString(); - decryptStart(null); - } - - private void decryptFromClipboardClicked() { - CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity()); - - // only decrypt if clipboard content is available and a pgp message or cleartext signature - if (clipboardText != null) { - Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText); - if (!matcher.matches()) { - matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(clipboardText); - } - if (matcher.matches()) { - mCiphertext = matcher.group(1); - decryptStart(null); - } else { - AppMsg.makeText(getActivity(), R.string.error_invalid_data, AppMsg.STYLE_INFO) - .show(); - } - } else { - AppMsg.makeText(getActivity(), R.string.error_invalid_data, AppMsg.STYLE_INFO) - .show(); - } - } - - @Override - protected void decryptStart(String passphrase) { - Log.d(Constants.TAG, "decryptStart"); - - // Send all information needed to service to decrypt in other thread - Intent intent = new Intent(getActivity(), KeychainIntentService.class); - - // fill values for this action - Bundle data = new Bundle(); - - intent.setAction(KeychainIntentService.ACTION_DECRYPT_VERIFY); - - // data - data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_BYTES); - data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes()); - data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, passphrase); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after encrypting is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), - getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get returned data bundle - Bundle returnData = message.getData(); - - PgpDecryptVerifyResult decryptVerifyResult = - returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT); - - if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) { - showPassphraseDialog(decryptVerifyResult.getKeyIdPassphraseNeeded()); - } else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == - decryptVerifyResult.getStatus()) { - showPassphraseDialog(Id.key.symmetric); - } else { - AppMsg.makeText(getActivity(), R.string.decryption_successful, - AppMsg.STYLE_INFO).show(); - - byte[] decryptedMessage = returnData - .getByteArray(KeychainIntentService.RESULT_DECRYPTED_BYTES); - mMessage.setText(new String(decryptedMessage)); - mMessage.setHorizontallyScrolling(false); - - OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult(); - - // display signature result in activity - onSignatureResult(signatureResult); - } - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - saveHandler.showProgressDialog(getActivity()); - - // start service with intent - getActivity().startService(intent); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java deleted file mode 100644 index c875818e3..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.graphics.Color; -import android.os.Bundle; -import android.support.v4.app.ActionBarDrawerToggle; -import android.support.v4.view.GravityCompat; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBarActivity; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.TextView; - -import com.beardedhen.androidbootstrap.FontAwesomeText; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; - -public class DrawerActivity extends ActionBarActivity { - private DrawerLayout mDrawerLayout; - private ListView mDrawerList; - private ActionBarDrawerToggle mDrawerToggle; - - private CharSequence mDrawerTitle; - private CharSequence mTitle; - private boolean mIsDrawerLocked = false; - - private Class mSelectedItem; - - private static final int MENU_ID_PREFERENCE = 222; - private static final int MENU_ID_HELP = 223; - - protected void setupDrawerNavigation(Bundle savedInstanceState) { - mDrawerTitle = getString(R.string.app_name); - mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); - mDrawerList = (ListView) findViewById(R.id.left_drawer); - ViewGroup viewGroup = (ViewGroup) findViewById(R.id.content_frame); - int leftMarginLoaded = ((ViewGroup.MarginLayoutParams) viewGroup.getLayoutParams()).leftMargin; - int leftMarginInTablets = (int) getResources().getDimension(R.dimen.drawer_size); - int errorInMarginAllowed = 5; - - // if the left margin of the loaded layout is close to the - // one used in tablets then set drawer as open and locked - if (Math.abs(leftMarginLoaded - leftMarginInTablets) < errorInMarginAllowed) { - mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN, mDrawerList); - mDrawerLayout.setScrimColor(Color.TRANSPARENT); - mIsDrawerLocked = true; - } else { - // set a custom shadow that overlays the main content when the drawer opens - mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); - mIsDrawerLocked = false; - } - - NavItem mItemIconTexts[] = new NavItem[]{ - new NavItem("fa-user", getString(R.string.nav_contacts)), - new NavItem("fa-lock", getString(R.string.nav_encrypt)), - new NavItem("fa-unlock", getString(R.string.nav_decrypt)), - new NavItem("fa-android", getString(R.string.nav_apps))}; - - mDrawerList.setAdapter(new NavigationDrawerAdapter(this, R.layout.drawer_list_item, - mItemIconTexts)); - - mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); - - // enable ActionBar app icon to behave as action to toggle nav drawer - // if the drawer is not locked - if (!mIsDrawerLocked) { - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); - } - - // ActionBarDrawerToggle ties together the the proper interactions - // between the sliding drawer and the action bar app icon - mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */ - mDrawerLayout, /* DrawerLayout object */ - R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */ - R.string.drawer_open, /* "open drawer" description for accessibility */ - R.string.drawer_close /* "close drawer" description for accessibility */ - ) { - public void onDrawerClosed(View view) { - getSupportActionBar().setTitle(mTitle); - - callIntentForDrawerItem(mSelectedItem); - } - - public void onDrawerOpened(View drawerView) { - mTitle = getSupportActionBar().getTitle(); - getSupportActionBar().setTitle(mDrawerTitle); - // creates call to onPrepareOptionsMenu() - supportInvalidateOptionsMenu(); - } - }; - - if (!mIsDrawerLocked) { - mDrawerLayout.setDrawerListener(mDrawerToggle); - } else { - // If the drawer is locked open make it un-focusable - // so that it doesn't consume all the Back button presses - mDrawerLayout.setFocusableInTouchMode(false); - } - } - - /** - * Uses startActivity to call the Intent of the given class - * - * @param drawerItem the class of the drawer item you want to load. Based on Constants.DrawerItems.* - */ - public void callIntentForDrawerItem(Class drawerItem) { - // creates call to onPrepareOptionsMenu() - supportInvalidateOptionsMenu(); - - // call intent activity if selected - if (drawerItem != null) { - finish(); - overridePendingTransition(0, 0); - - Intent intent = new Intent(this, drawerItem); - startActivity(intent); - - // disable animation of activity start - overridePendingTransition(0, 0); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - if (mDrawerToggle == null) { - return super.onCreateOptionsMenu(menu); - } - - menu.add(42, MENU_ID_PREFERENCE, 100, R.string.menu_preferences); - menu.add(42, MENU_ID_HELP, 101, R.string.menu_help); - - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (mDrawerToggle == null) { - return super.onOptionsItemSelected(item); - } - - // The action bar home/up action should open or close the drawer. - // ActionBarDrawerToggle will take care of this. - if (mDrawerToggle.onOptionsItemSelected(item)) { - return true; - } - - switch (item.getItemId()) { - case MENU_ID_PREFERENCE: { - Intent intent = new Intent(this, PreferencesActivity.class); - startActivity(intent); - return true; - } - case MENU_ID_HELP: { - Intent intent = new Intent(this, HelpActivity.class); - startActivity(intent); - return true; - } - default: - return super.onOptionsItemSelected(item); - } - } - - /** - * The click listener for ListView in the navigation drawer - */ - private class DrawerItemClickListener implements ListView.OnItemClickListener { - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - selectItem(position); - } - } - - private void selectItem(int position) { - // update selected item and title, then close the drawer - mDrawerList.setItemChecked(position, true); - // set selected class - mSelectedItem = Constants.DrawerItems.ARRAY[position]; - - // setTitle(mDrawerTitles[position]); - // If drawer isn't locked just close the drawer and - // it will move to the selected item by itself (via drawer toggle listener) - if (!mIsDrawerLocked) { - mDrawerLayout.closeDrawer(mDrawerList); - // else move to the selected item yourself - } else { - callIntentForDrawerItem(mSelectedItem); - } - } - - /** - * When using the ActionBarDrawerToggle, you must call it during onPostCreate() and - * onConfigurationChanged()... - */ - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - // Sync the toggle state after onRestoreInstanceState has occurred. - if (mDrawerToggle != null) { - mDrawerToggle.syncState(); - } - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - // Pass any configuration change to the drawer toggles - if (mDrawerToggle != null) { - mDrawerToggle.onConfigurationChanged(newConfig); - } - } - - private class NavItem { - public String icon; - public String title; - - public NavItem(String icon, String title) { - super(); - this.icon = icon; - this.title = title; - } - } - - private class NavigationDrawerAdapter extends ArrayAdapter<NavItem> { - Context mContext; - int mLayoutResourceId; - NavItem mData[] = null; - - public NavigationDrawerAdapter(Context context, int layoutResourceId, NavItem[] data) { - super(context, layoutResourceId, data); - this.mLayoutResourceId = layoutResourceId; - this.mContext = context; - this.mData = data; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View row = convertView; - NavItemHolder holder; - - if (row == null) { - LayoutInflater inflater = ((Activity) mContext).getLayoutInflater(); - row = inflater.inflate(mLayoutResourceId, parent, false); - - holder = new NavItemHolder(); - holder.mImg = (FontAwesomeText) row.findViewById(R.id.drawer_item_icon); - holder.mTxtTitle = (TextView) row.findViewById(R.id.drawer_item_text); - - row.setTag(holder); - } else { - holder = (NavItemHolder) row.getTag(); - } - - NavItem item = mData[position]; - holder.mTxtTitle.setText(item.title); - holder.mImg.setIcon(item.icon); - - return row; - } - - } - - static class NavItemHolder { - FontAwesomeText mImg; - TextView mTxtTitle; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java deleted file mode 100644 index 93d5688b9..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ /dev/null @@ -1,760 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.support.v4.app.ActivityCompat; -import android.support.v7.app.ActionBarActivity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.LinearLayout; - -import com.beardedhen.androidbootstrap.BootstrapButton; -import com.devspark.appmsg.AppMsg; - -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.helper.ExportHelper; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.service.SaveKeyringParcel; -import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; -import org.sufficientlysecure.keychain.ui.widget.Editor; -import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; -import org.sufficientlysecure.keychain.ui.widget.KeyEditor; -import org.sufficientlysecure.keychain.ui.widget.SectionView; -import org.sufficientlysecure.keychain.ui.widget.UserIdEditor; -import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.Vector; - -public class EditKeyActivity extends ActionBarActivity implements EditorListener { - - // Actions for internal use only: - public static final String ACTION_CREATE_KEY = Constants.INTENT_PREFIX + "CREATE_KEY"; - public static final String ACTION_EDIT_KEY = Constants.INTENT_PREFIX + "EDIT_KEY"; - - // possible extra keys - public static final String EXTRA_USER_IDS = "user_ids"; - public static final String EXTRA_NO_PASSPHRASE = "no_passphrase"; - public static final String EXTRA_GENERATE_DEFAULT_KEYS = "generate_default_keys"; - - // EDIT - private Uri mDataUri; - - private PGPSecretKeyRing mKeyRing = null; - - private SectionView mUserIdsView; - private SectionView mKeysView; - - private String mCurrentPassphrase = null; - private String mNewPassphrase = null; - private String mSavedNewPassphrase = null; - private boolean mIsPassphraseSet; - private boolean mNeedsSaving; - private boolean mIsBrandNewKeyring = false; - - private BootstrapButton mChangePassphrase; - - private CheckBox mNoPassphrase; - - Vector<String> mUserIds; - Vector<PGPSecretKey> mKeys; - Vector<Integer> mKeysUsages; - boolean mMasterCanSign = true; - - ExportHelper mExportHelper; - - public boolean needsSaving() { - mNeedsSaving = (mUserIdsView == null) ? false : mUserIdsView.needsSaving(); - mNeedsSaving |= (mKeysView == null) ? false : mKeysView.needsSaving(); - mNeedsSaving |= hasPassphraseChanged(); - mNeedsSaving |= mIsBrandNewKeyring; - return mNeedsSaving; - } - - - public void somethingChanged() { - ActivityCompat.invalidateOptionsMenu(this); - } - - public void onDeleted(Editor e, boolean wasNewItem) { - somethingChanged(); - } - - public void onEdited() { - somethingChanged(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mExportHelper = new ExportHelper(this); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.btn_save, R.drawable.ic_action_save, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Save - saveClicked(); - } - }, R.string.menu_key_edit_cancel, R.drawable.ic_action_cancel, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Cancel - cancelClicked(); - } - } - ); - - mUserIds = new Vector<String>(); - mKeys = new Vector<PGPSecretKey>(); - mKeysUsages = new Vector<Integer>(); - - // Catch Intents opened from other apps - Intent intent = getIntent(); - String action = intent.getAction(); - if (ACTION_CREATE_KEY.equals(action)) { - handleActionCreateKey(intent); - } else if (ACTION_EDIT_KEY.equals(action)) { - handleActionEditKey(intent); - } - } - - /** - * Handle intent action to create new key - * - * @param intent - */ - private void handleActionCreateKey(Intent intent) { - Bundle extras = intent.getExtras(); - - mCurrentPassphrase = ""; - mIsBrandNewKeyring = true; - - if (extras != null) { - // if userId is given, prefill the fields - if (extras.containsKey(EXTRA_USER_IDS)) { - Log.d(Constants.TAG, "UserIds are given!"); - mUserIds.add(extras.getString(EXTRA_USER_IDS)); - } - - // if no passphrase is given - if (extras.containsKey(EXTRA_NO_PASSPHRASE)) { - boolean noPassphrase = extras.getBoolean(EXTRA_NO_PASSPHRASE); - if (noPassphrase) { - // check "no passphrase" checkbox and remove button - mNoPassphrase.setChecked(true); - mChangePassphrase.setVisibility(View.GONE); - } - } - - // generate key - if (extras.containsKey(EXTRA_GENERATE_DEFAULT_KEYS)) { - boolean generateDefaultKeys = extras.getBoolean(EXTRA_GENERATE_DEFAULT_KEYS); - if (generateDefaultKeys) { - - // Send all information needed to service generate keys in other thread - final Intent serviceIntent = new Intent(this, KeychainIntentService.class); - serviceIntent.setAction(KeychainIntentService.ACTION_GENERATE_DEFAULT_RSA_KEYS); - - // fill values for this action - Bundle data = new Bundle(); - data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, - mCurrentPassphrase); - - serviceIntent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after generating is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( - this, getResources().getQuantityString(R.plurals.progress_generating, 1), - ProgressDialog.STYLE_HORIZONTAL, true, - - new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - // Stop key generation on cancel - stopService(serviceIntent); - EditKeyActivity.this.setResult(Activity.RESULT_CANCELED); - EditKeyActivity.this.finish(); - } - }) { - - @Override - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get new key from data bundle returned from service - Bundle data = message.getData(); - - ArrayList<PGPSecretKey> newKeys = - PgpConversionHelper.BytesToPGPSecretKeyList(data - .getByteArray(KeychainIntentService.RESULT_NEW_KEY)); - - ArrayList<Integer> keyUsageFlags = data.getIntegerArrayList( - KeychainIntentService.RESULT_KEY_USAGES); - - if (newKeys.size() == keyUsageFlags.size()) { - for (int i = 0; i < newKeys.size(); ++i) { - mKeys.add(newKeys.get(i)); - mKeysUsages.add(keyUsageFlags.get(i)); - } - } - - buildLayout(true); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - serviceIntent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - saveHandler.showProgressDialog(this); - - // start service with intent - startService(serviceIntent); - } - } - } else { - buildLayout(false); - } - } - - /** - * Handle intent action to edit existing key - * - * @param intent - */ - private void handleActionEditKey(Intent intent) { - mDataUri = intent.getData(); - if (mDataUri == null) { - Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!"); - finish(); - } else { - Log.d(Constants.TAG, "uri: " + mDataUri); - - // get master key id using row id - long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri); - finallyEdit(masterKeyId); - } - } - - @SuppressWarnings("unchecked") - private void finallyEdit(final long masterKeyId) { - if (masterKeyId != 0) { - PGPSecretKey masterKey = null; - mKeyRing = ProviderHelper.getPGPSecretKeyRing(this, masterKeyId); - if (mKeyRing != null) { - masterKey = mKeyRing.getSecretKey(); - mMasterCanSign = PgpKeyHelper.isCertificationKey(mKeyRing.getSecretKey()); - for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(mKeyRing.getSecretKeys())) { - mKeys.add(key); - mKeysUsages.add(-1); // get usage when view is created - } - } else { - Log.e(Constants.TAG, "Keyring not found with masterKeyId: " + masterKeyId); - AppMsg.makeText(this, R.string.error_no_secret_key_found, AppMsg.STYLE_ALERT).show(); - // TODO - } - if (masterKey != null) { - boolean isSet = false; - for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) { - Log.d(Constants.TAG, "Added userId " + userId); - if (!isSet) { - isSet = true; - String[] parts = PgpKeyHelper.splitUserId(userId); - if (parts[0] != null) { - setTitle(parts[0]); - } - } - mUserIds.add(userId); - } - } - } - - mCurrentPassphrase = ""; - buildLayout(false); - - mIsPassphraseSet = PassphraseCacheService.hasPassphrase(this, masterKeyId); - if (!mIsPassphraseSet) { - // check "no passphrase" checkbox and remove button - mNoPassphrase.setChecked(true); - mChangePassphrase.setVisibility(View.GONE); - } - } - - /** - * Shows the dialog to set a new passphrase - */ - private void showSetPassphraseDialog() { - // Message is received after passphrase is cached - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) { - Bundle data = message.getData(); - - // set new returned passphrase! - mNewPassphrase = data - .getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE); - - updatePassphraseButtonText(); - somethingChanged(); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - // set title based on isPassphraseSet() - int title; - if (isPassphraseSet()) { - title = R.string.title_change_passphrase; - } else { - title = R.string.title_set_passphrase; - } - - SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance( - messenger, title); - - setPassphraseDialog.show(getSupportFragmentManager(), "setPassphraseDialog"); - } - - /** - * Build layout based on mUserId, mKeys and mKeysUsages Vectors. It creates Views for every user - * id and key. - * - * @param newKeys - */ - private void buildLayout(boolean newKeys) { - setContentView(R.layout.edit_key_activity); - - // find views - mChangePassphrase = (BootstrapButton) findViewById(R.id.edit_key_btn_change_passphrase); - mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase); - // Build layout based on given userIds and keys - - LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - LinearLayout container = (LinearLayout) findViewById(R.id.edit_key_container); - if (mIsPassphraseSet) { - mChangePassphrase.setText(getString(R.string.btn_change_passphrase)); - } - mUserIdsView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false); - mUserIdsView.setType(Id.type.user_id); - mUserIdsView.setCanBeEdited(mMasterCanSign); - mUserIdsView.setUserIds(mUserIds); - mUserIdsView.setEditorListener(this); - container.addView(mUserIdsView); - mKeysView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false); - mKeysView.setType(Id.type.key); - mKeysView.setCanBeEdited(mMasterCanSign); - mKeysView.setKeys(mKeys, mKeysUsages, newKeys); - mKeysView.setEditorListener(this); - container.addView(mKeysView); - - updatePassphraseButtonText(); - - mChangePassphrase.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - showSetPassphraseDialog(); - } - }); - - // disable passphrase when no passphrase checkbox is checked! - mNoPassphrase.setOnCheckedChangeListener(new OnCheckedChangeListener() { - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - // remove passphrase - mSavedNewPassphrase = mNewPassphrase; - mNewPassphrase = ""; - mChangePassphrase.setVisibility(View.GONE); - } else { - mNewPassphrase = mSavedNewPassphrase; - mChangePassphrase.setVisibility(View.VISIBLE); - } - somethingChanged(); - } - }); - } - - private long getMasterKeyId() { - if (mKeysView.getEditors().getChildCount() == 0) { - return 0; - } - return ((KeyEditor) mKeysView.getEditors().getChildAt(0)).getValue().getKeyID(); - } - - public boolean isPassphraseSet() { - if (mNoPassphrase.isChecked()) { - return true; - } else if ((mIsPassphraseSet) - || (mNewPassphrase != null && !mNewPassphrase.equals(""))) { - return true; - } else { - return false; - } - } - - public boolean hasPassphraseChanged() { - if (mNoPassphrase != null) { - if (mNoPassphrase.isChecked()) { - return mIsPassphraseSet; - } else { - return (mNewPassphrase != null && !mNewPassphrase.equals("")); - } - } else { - return false; - } - } - - private void saveClicked() { - final long masterKeyId = getMasterKeyId(); - if (needsSaving()) { //make sure, as some versions don't support invalidateOptionsMenu - try { - if (!isPassphraseSet()) { - throw new PgpGeneralException(this.getString(R.string.set_a_passphrase)); - } - - String passphrase; - if (mIsPassphraseSet) { - passphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId); - } else { - passphrase = ""; - } - if (passphrase == null) { - PassphraseDialogFragment.show(this, masterKeyId, - new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase( - EditKeyActivity.this, masterKeyId); - checkEmptyIDsWanted(); - } - } - }); - } else { - mCurrentPassphrase = passphrase; - checkEmptyIDsWanted(); - } - } catch (PgpGeneralException e) { - AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()), - AppMsg.STYLE_ALERT).show(); - } - } else { - AppMsg.makeText(this, R.string.error_change_something_first, AppMsg.STYLE_ALERT).show(); - } - } - - private void checkEmptyIDsWanted() { - try { - ArrayList<String> userIDs = getUserIds(mUserIdsView); - List<Boolean> newIDs = mUserIdsView.getNewIDFlags(); - ArrayList<String> originalIDs = mUserIdsView.getOriginalIDs(); - int curID = 0; - for (String userID : userIDs) { - if (userID.equals("") && (!userID.equals(originalIDs.get(curID)) || newIDs.get(curID))) { - AlertDialog.Builder alert = new AlertDialog.Builder( - EditKeyActivity.this); - - alert.setIcon(R.drawable.ic_dialog_alert_holo_light); - alert.setTitle(R.string.warning); - alert.setMessage(EditKeyActivity.this.getString(R.string.ask_empty_id_ok)); - - alert.setPositiveButton(EditKeyActivity.this.getString(android.R.string.yes), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.dismiss(); - finallySaveClicked(); - } - } - ); - alert.setNegativeButton(this.getString(android.R.string.no), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.dismiss(); - } - } - ); - alert.setCancelable(false); - alert.create().show(); - return; - } - curID++; - } - } catch (PgpGeneralException e) { - Log.e(Constants.TAG, getString(R.string.error_message, e.getMessage())); - AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()), AppMsg.STYLE_ALERT).show(); - } - finallySaveClicked(); - } - - private boolean[] toPrimitiveArray(final List<Boolean> booleanList) { - final boolean[] primitives = new boolean[booleanList.size()]; - int index = 0; - for (Boolean object : booleanList) { - primitives[index++] = object; - } - return primitives; - } - - private void finallySaveClicked() { - try { - // Send all information needed to service to edit key in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING); - - SaveKeyringParcel saveParams = new SaveKeyringParcel(); - saveParams.userIDs = getUserIds(mUserIdsView); - saveParams.originalIDs = mUserIdsView.getOriginalIDs(); - saveParams.deletedIDs = mUserIdsView.getDeletedIDs(); - saveParams.newIDs = toPrimitiveArray(mUserIdsView.getNewIDFlags()); - saveParams.primaryIDChanged = mUserIdsView.primaryChanged(); - saveParams.moddedKeys = toPrimitiveArray(mKeysView.getNeedsSavingArray()); - saveParams.deletedKeys = mKeysView.getDeletedKeys(); - saveParams.keysExpiryDates = getKeysExpiryDates(mKeysView); - saveParams.keysUsages = getKeysUsages(mKeysView); - saveParams.newPassphrase = mNewPassphrase; - saveParams.oldPassphrase = mCurrentPassphrase; - saveParams.newKeys = toPrimitiveArray(mKeysView.getNewKeysArray()); - saveParams.keys = getKeys(mKeysView); - saveParams.originalPrimaryID = mUserIdsView.getOriginalPrimaryID(); - - - // fill values for this action - Bundle data = new Bundle(); - data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, mMasterCanSign); - data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, saveParams); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after saving is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, - getString(R.string.progress_saving), ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - Intent data = new Intent(); - - // return uri pointing to new created key - Uri uri = KeychainContract.KeyRings.buildGenericKeyRingUri( - String.valueOf(getMasterKeyId())); - data.setData(uri); - - setResult(RESULT_OK, data); - finish(); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - saveHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } catch (PgpGeneralException e) { - Log.e(Constants.TAG, getString(R.string.error_message, e.getMessage())); - AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()), - AppMsg.STYLE_ALERT).show(); - } - } - - private void cancelClicked() { - if (needsSaving()) { //ask if we want to save - AlertDialog.Builder alert = new AlertDialog.Builder( - EditKeyActivity.this); - - alert.setIcon(R.drawable.ic_dialog_alert_holo_light); - alert.setTitle(R.string.warning); - alert.setMessage(EditKeyActivity.this.getString(R.string.ask_save_changed_key)); - - alert.setPositiveButton(EditKeyActivity.this.getString(android.R.string.yes), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.dismiss(); - saveClicked(); - } - }); - alert.setNegativeButton(this.getString(android.R.string.no), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.dismiss(); - setResult(RESULT_CANCELED); - finish(); - } - }); - alert.setCancelable(false); - alert.create().show(); - } else { - setResult(RESULT_CANCELED); - finish(); - } - } - - /** - * Returns user ids from the SectionView - * - * @param userIdsView - * @return - */ - private ArrayList<String> getUserIds(SectionView userIdsView) throws PgpGeneralException { - ArrayList<String> userIds = new ArrayList<String>(); - - ViewGroup userIdEditors = userIdsView.getEditors(); - - boolean gotMainUserId = false; - for (int i = 0; i < userIdEditors.getChildCount(); ++i) { - UserIdEditor editor = (UserIdEditor) userIdEditors.getChildAt(i); - String userId; - userId = editor.getValue(); - - if (editor.isMainUserId()) { - userIds.add(0, userId); - gotMainUserId = true; - } else { - userIds.add(userId); - } - } - - if (userIds.size() == 0) { - throw new PgpGeneralException(getString(R.string.error_key_needs_a_user_id)); - } - - if (!gotMainUserId) { - throw new PgpGeneralException(getString(R.string.error_main_user_id_must_not_be_empty)); - } - - return userIds; - } - - /** - * Returns keys from the SectionView - * - * @param keysView - * @return - */ - private ArrayList<PGPSecretKey> getKeys(SectionView keysView) throws PgpGeneralException { - ArrayList<PGPSecretKey> keys = new ArrayList<PGPSecretKey>(); - - ViewGroup keyEditors = keysView.getEditors(); - - if (keyEditors.getChildCount() == 0) { - throw new PgpGeneralException(getString(R.string.error_key_needs_master_key)); - } - - for (int i = 0; i < keyEditors.getChildCount(); ++i) { - KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i); - keys.add(editor.getValue()); - } - - return keys; - } - - /** - * Returns usage selections of keys from the SectionView - * - * @param keysView - * @return - */ - private ArrayList<Integer> getKeysUsages(SectionView keysView) throws PgpGeneralException { - ArrayList<Integer> keysUsages = new ArrayList<Integer>(); - - ViewGroup keyEditors = keysView.getEditors(); - - if (keyEditors.getChildCount() == 0) { - throw new PgpGeneralException(getString(R.string.error_key_needs_master_key)); - } - - for (int i = 0; i < keyEditors.getChildCount(); ++i) { - KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i); - keysUsages.add(editor.getUsage()); - } - - return keysUsages; - } - - private ArrayList<GregorianCalendar> getKeysExpiryDates(SectionView keysView) throws PgpGeneralException { - ArrayList<GregorianCalendar> keysExpiryDates = new ArrayList<GregorianCalendar>(); - - ViewGroup keyEditors = keysView.getEditors(); - - if (keyEditors.getChildCount() == 0) { - throw new PgpGeneralException(getString(R.string.error_key_needs_master_key)); - } - - for (int i = 0; i < keyEditors.getChildCount(); ++i) { - KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i); - keysExpiryDates.add(editor.getExpiryDate()); - } - - return keysExpiryDates; - } - - private void updatePassphraseButtonText() { - mChangePassphrase.setText(isPassphraseSet() ? getString(R.string.btn_change_passphrase) - : getString(R.string.btn_set_passphrase)); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java deleted file mode 100644 index a03c7d797..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.view.PagerTabStrip; -import android.support.v4.view.ViewPager; -import android.widget.Toast; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.helper.FileHelper; -import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; -import org.sufficientlysecure.keychain.util.Log; - -public class EncryptActivity extends DrawerActivity implements - EncryptSymmetricFragment.OnSymmetricKeySelection, - EncryptAsymmetricFragment.OnAsymmetricKeySelection, - EncryptActivityInterface { - - /* Intents */ - public static final String ACTION_ENCRYPT = Constants.INTENT_PREFIX + "ENCRYPT"; - - /* EXTRA keys for input */ - public static final String EXTRA_TEXT = "text"; - - // enables ASCII Armor for file encryption when uri is given - public static final String EXTRA_ASCII_ARMOR = "ascii_armor"; - - // preselect ids, for internal use - public static final String EXTRA_SIGNATURE_KEY_ID = "signature_key_id"; - public static final String EXTRA_ENCRYPTION_KEY_IDS = "encryption_key_ids"; - - // view - ViewPager mViewPagerMode; - PagerTabStrip mPagerTabStripMode; - PagerTabStripAdapter mTabsAdapterMode; - ViewPager mViewPagerContent; - PagerTabStrip mPagerTabStripContent; - PagerTabStripAdapter mTabsAdapterContent; - - // tabs - Bundle mAsymmetricFragmentBundle = new Bundle(); - Bundle mSymmetricFragmentBundle = new Bundle(); - Bundle mMessageFragmentBundle = new Bundle(); - Bundle mFileFragmentBundle = new Bundle(); - int mSwitchToMode = PAGER_MODE_ASYMMETRIC; - int mSwitchToContent = PAGER_CONTENT_MESSAGE; - - private static final int PAGER_MODE_ASYMMETRIC = 0; - private static final int PAGER_MODE_SYMMETRIC = 1; - private static final int PAGER_CONTENT_MESSAGE = 0; - private static final int PAGER_CONTENT_FILE = 1; - - // model useb by message and file fragment - private long mEncryptionKeyIds[] = null; - private long mSigningKeyId = Id.key.none; - private String mPassphrase; - private String mPassphraseAgain; - - @Override - public void onSigningKeySelected(long signingKeyId) { - mSigningKeyId = signingKeyId; - } - - @Override - public void onEncryptionKeysSelected(long[] encryptionKeyIds) { - mEncryptionKeyIds = encryptionKeyIds; - } - - @Override - public void onPassphraseUpdate(String passphrase) { - mPassphrase = passphrase; - } - - @Override - public void onPassphraseAgainUpdate(String passphrase) { - mPassphraseAgain = passphrase; - } - - @Override - public boolean isModeSymmetric() { - if (PAGER_MODE_SYMMETRIC == mViewPagerMode.getCurrentItem()) { - return true; - } else { - return false; - } - } - - @Override - public long getSignatureKey() { - return mSigningKeyId; - } - - @Override - public long[] getEncryptionKeys() { - return mEncryptionKeyIds; - } - - @Override - public String getPassphrase() { - return mPassphrase; - } - - @Override - public String getPassphraseAgain() { - return mPassphraseAgain; - } - - - private void initView() { - mViewPagerMode = (ViewPager) findViewById(R.id.encrypt_pager_mode); - mPagerTabStripMode = (PagerTabStrip) findViewById(R.id.encrypt_pager_tab_strip_mode); - mViewPagerContent = (ViewPager) findViewById(R.id.encrypt_pager_content); - mPagerTabStripContent = (PagerTabStrip) findViewById(R.id.encrypt_pager_tab_strip_content); - - mTabsAdapterMode = new PagerTabStripAdapter(this); - mViewPagerMode.setAdapter(mTabsAdapterMode); - mTabsAdapterContent = new PagerTabStripAdapter(this); - mViewPagerContent.setAdapter(mTabsAdapterContent); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.encrypt_activity); - - // set actionbar without home button if called from another app - ActionBarHelper.setBackButton(this); - - initView(); - - setupDrawerNavigation(savedInstanceState); - - // Handle intent actions - handleActions(getIntent()); - - mTabsAdapterMode.addTab(EncryptAsymmetricFragment.class, - mAsymmetricFragmentBundle, getString(R.string.label_asymmetric)); - mTabsAdapterMode.addTab(EncryptSymmetricFragment.class, - mSymmetricFragmentBundle, getString(R.string.label_symmetric)); - mViewPagerMode.setCurrentItem(mSwitchToMode); - - mTabsAdapterContent.addTab(EncryptMessageFragment.class, - mMessageFragmentBundle, getString(R.string.label_message)); - mTabsAdapterContent.addTab(EncryptFileFragment.class, - mFileFragmentBundle, getString(R.string.label_file)); - mViewPagerContent.setCurrentItem(mSwitchToContent); - } - - /** - * Handles all actions with this intent - * - * @param intent - */ - private void handleActions(Intent intent) { - String action = intent.getAction(); - Bundle extras = intent.getExtras(); - String type = intent.getType(); - Uri uri = intent.getData(); - - if (extras == null) { - extras = new Bundle(); - } - - /* - * Android's Action - */ - if (Intent.ACTION_SEND.equals(action) && type != null) { - // When sending to APG Encrypt via share menu - if ("text/plain".equals(type)) { - // Plain text - String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); - if (sharedText != null) { - // handle like normal text encryption, override action and extras to later - // executeServiceMethod ACTION_ENCRYPT in main actions - extras.putString(EXTRA_TEXT, sharedText); - extras.putBoolean(EXTRA_ASCII_ARMOR, true); - action = ACTION_ENCRYPT; - } - } else { - // Files via content provider, override uri and action - uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); - action = ACTION_ENCRYPT; - } - } - - if (extras.containsKey(EXTRA_ASCII_ARMOR)) { - boolean requestAsciiArmor = extras.getBoolean(EXTRA_ASCII_ARMOR, true); - mFileFragmentBundle.putBoolean(EncryptFileFragment.ARG_ASCII_ARMOR, requestAsciiArmor); - } - - String textData = extras.getString(EXTRA_TEXT); - - long signatureKeyId = extras.getLong(EXTRA_SIGNATURE_KEY_ID); - long[] encryptionKeyIds = extras.getLongArray(EXTRA_ENCRYPTION_KEY_IDS); - - // preselect keys given by intent - mAsymmetricFragmentBundle.putLongArray(EncryptAsymmetricFragment.ARG_ENCRYPTION_KEY_IDS, - encryptionKeyIds); - mAsymmetricFragmentBundle.putLong(EncryptAsymmetricFragment.ARG_SIGNATURE_KEY_ID, - signatureKeyId); - mSwitchToMode = PAGER_MODE_ASYMMETRIC; - - /** - * Main Actions - */ - if (ACTION_ENCRYPT.equals(action) && textData != null) { - // encrypt text based on given extra - mMessageFragmentBundle.putString(EncryptMessageFragment.ARG_TEXT, textData); - mSwitchToContent = PAGER_CONTENT_MESSAGE; - } else if (ACTION_ENCRYPT.equals(action) && uri != null) { - // encrypt file based on Uri - - // get file path from uri - String path = FileHelper.getPath(this, uri); - - if (path != null) { - mFileFragmentBundle.putString(EncryptFileFragment.ARG_FILENAME, path); - mSwitchToContent = PAGER_CONTENT_FILE; - } else { - Log.e(Constants.TAG, - "Direct binary data without actual file in filesystem is not supported " + - "by Intents. Please use the Remote Service API!"); - Toast.makeText(this, R.string.error_only_files_are_supported, Toast.LENGTH_LONG) - .show(); - // end activity - finish(); - } - } else { - Log.e(Constants.TAG, - "Include the extra 'text' or an Uri with setData() in your Intent!"); - } - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java deleted file mode 100644 index 0786b3a16..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivityInterface.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -public interface EncryptActivityInterface { - - public boolean isModeSymmetric(); - - public long getSignatureKey(); - public long[] getEncryptionKeys(); - - public String getPassphrase(); - public String getPassphraseAgain(); - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java deleted file mode 100644 index 8400cf397..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; - -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.ProviderHelper; - -import java.util.HashMap; -import java.util.Vector; - -public class EncryptAsymmetricFragment extends Fragment { - public static final String ARG_SIGNATURE_KEY_ID = "signature_key_id"; - public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids"; - - public static final int RESULT_CODE_PUBLIC_KEYS = 0x00007001; - public static final int RESULT_CODE_SECRET_KEYS = 0x00007002; - - OnAsymmetricKeySelection mKeySelectionListener; - - // view - private BootstrapButton mSelectKeysButton; - private CheckBox mSign; - private TextView mMainUserId; - private TextView mMainUserIdRest; - - // model - private long mSecretKeyId = Id.key.none; - private long mEncryptionKeyIds[] = null; - - // Container Activity must implement this interface - public interface OnAsymmetricKeySelection { - public void onSigningKeySelected(long signingKeyId); - - public void onEncryptionKeysSelected(long[] encryptionKeyIds); - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mKeySelectionListener = (OnAsymmetricKeySelection) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement OnAsymmetricKeySelection"); - } - } - - private void setSignatureKeyId(long signatureKeyId) { - mSecretKeyId = signatureKeyId; - // update key selection in EncryptActivity - mKeySelectionListener.onSigningKeySelected(signatureKeyId); - updateView(); - } - - private void setEncryptionKeyIds(long[] encryptionKeyIds) { - mEncryptionKeyIds = encryptionKeyIds; - // update key selection in EncryptActivity - mKeySelectionListener.onEncryptionKeysSelected(encryptionKeyIds); - updateView(); - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false); - - mSelectKeysButton = (BootstrapButton) view.findViewById(R.id.btn_selectEncryptKeys); - mSign = (CheckBox) view.findViewById(R.id.sign); - mMainUserId = (TextView) view.findViewById(R.id.mainUserId); - mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - mSelectKeysButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - selectPublicKeys(); - } - }); - mSign.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - CheckBox checkBox = (CheckBox) v; - if (checkBox.isChecked()) { - selectSecretKey(); - } else { - setSignatureKeyId(Id.key.none); - } - } - }); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - long signatureKeyId = getArguments().getLong(ARG_SIGNATURE_KEY_ID); - long[] encryptionKeyIds = getArguments().getLongArray(ARG_ENCRYPTION_KEY_IDS); - - // preselect keys given by arguments (given by Intent to EncryptActivity) - preselectKeys(signatureKeyId, encryptionKeyIds); - } - - /** - * If an Intent gives a signatureKeyId and/or encryptionKeyIds, preselect those! - * - * @param preselectedSignatureKeyId - * @param preselectedEncryptionKeyIds - */ - private void preselectKeys(long preselectedSignatureKeyId, long[] preselectedEncryptionKeyIds) { - if (preselectedSignatureKeyId != 0) { - // TODO: don't use bouncy castle objects! - PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingWithKeyId(getActivity(), - preselectedSignatureKeyId); - PGPSecretKey masterKey; - if (keyRing != null) { - masterKey = keyRing.getSecretKey(); - if (masterKey != null) { - Vector<PGPSecretKey> signKeys = PgpKeyHelper.getUsableSigningKeys(keyRing); - if (signKeys.size() > 0) { - setSignatureKeyId(masterKey.getKeyID()); - } - } - } - } - - if (preselectedEncryptionKeyIds != null) { - Vector<Long> goodIds = new Vector<Long>(); - for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) { - long id = ProviderHelper.getMasterKeyId(getActivity(), - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(preselectedEncryptionKeyIds[i])) - ); - // TODO check for available encrypt keys... is this even relevant? - goodIds.add(id); - } - if (goodIds.size() > 0) { - long[] keyIds = new long[goodIds.size()]; - for (int i = 0; i < goodIds.size(); ++i) { - keyIds[i] = goodIds.get(i); - } - setEncryptionKeyIds(keyIds); - } - } - } - - private void updateView() { - if (mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0) { - mSelectKeysButton.setText(getString(R.string.select_keys_button_default)); - } else { - mSelectKeysButton.setText(getResources().getQuantityString( - R.plurals.select_keys_button, mEncryptionKeyIds.length, - mEncryptionKeyIds.length)); - } - - if (mSecretKeyId == Id.key.none) { - mSign.setChecked(false); - mMainUserId.setText(""); - mMainUserIdRest.setText(""); - } else { - // See if we can get a user_id from a unified query - String userIdResult = (String) ProviderHelper.getUnifiedData( - getActivity(), mSecretKeyId, KeyRings.USER_ID, ProviderHelper.FIELD_TYPE_STRING); - String[] userId = PgpKeyHelper.splitUserId(userIdResult); - if (userId[0] != null) { - mMainUserId.setText(userId[0]); - } else { - mMainUserId.setText(getResources().getString(R.string.user_id_no_name)); - } - if (userId[1] != null) { - mMainUserIdRest.setText(userId[1]); - } else { - mMainUserIdRest.setText(""); - } - mSign.setChecked(true); - } - } - - private void selectPublicKeys() { - Intent intent = new Intent(getActivity(), SelectPublicKeyActivity.class); - Vector<Long> keyIds = new Vector<Long>(); - if (mSecretKeyId != 0) { - keyIds.add(mSecretKeyId); - } - if (mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0) { - for (int i = 0; i < mEncryptionKeyIds.length; ++i) { - keyIds.add(mEncryptionKeyIds[i]); - } - } - long[] initialKeyIds = null; - if (keyIds.size() > 0) { - initialKeyIds = new long[keyIds.size()]; - for (int i = 0; i < keyIds.size(); ++i) { - initialKeyIds[i] = keyIds.get(i); - } - } - intent.putExtra(SelectPublicKeyActivity.EXTRA_SELECTED_MASTER_KEY_IDS, initialKeyIds); - startActivityForResult(intent, Id.request.public_keys); - } - - private void selectSecretKey() { - Intent intent = new Intent(getActivity(), SelectSecretKeyActivity.class); - startActivityForResult(intent, Id.request.secret_keys); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case RESULT_CODE_PUBLIC_KEYS: { - if (resultCode == Activity.RESULT_OK) { - Bundle bundle = data.getExtras(); - setEncryptionKeyIds(bundle - .getLongArray(SelectPublicKeyActivity.RESULT_EXTRA_MASTER_KEY_IDS)); - } - break; - } - - case RESULT_CODE_SECRET_KEYS: { - if (resultCode == Activity.RESULT_OK) { - Uri uriMasterKey = data.getData(); - setSignatureKeyId(Long.valueOf(uriMasterKey.getLastPathSegment())); - } else { - setSignatureKeyId(Id.key.none); - } - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - - break; - } - } - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java deleted file mode 100644 index 470c85715..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFileFragment.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.Spinner; - -import com.beardedhen.androidbootstrap.BootstrapButton; -import com.devspark.appmsg.AppMsg; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.FileHelper; -import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; -import org.sufficientlysecure.keychain.util.Choice; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.File; - -public class EncryptFileFragment extends Fragment { - public static final String ARG_FILENAME = "filename"; - public static final String ARG_ASCII_ARMOR = "ascii_armor"; - - private static final int RESULT_CODE_FILE = 0x00007003; - - private EncryptActivityInterface mEncryptInterface; - - // view - private CheckBox mAsciiArmor = null; - private Spinner mFileCompression = null; - private EditText mFilename = null; - private CheckBox mDeleteAfter = null; - private CheckBox mShareAfter = null; - private BootstrapButton mBrowse = null; - private BootstrapButton mEncryptFile; - - private FileDialogFragment mFileDialog; - - // model - private String mInputFilename = null; - private String mOutputFilename = null; - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mEncryptInterface = (EncryptActivityInterface) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface"); - } - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.encrypt_file_fragment, container, false); - - mEncryptFile = (BootstrapButton) view.findViewById(R.id.action_encrypt_file); - mEncryptFile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - encryptClicked(); - } - }); - - mFilename = (EditText) view.findViewById(R.id.filename); - mBrowse = (BootstrapButton) view.findViewById(R.id.btn_browse); - mBrowse.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - FileHelper.openFile(EncryptFileFragment.this, mFilename.getText().toString(), "*/*", - Id.request.filename); - } - }); - - mFileCompression = (Spinner) view.findViewById(R.id.fileCompression); - Choice[] choices = new Choice[] { - new Choice(Id.choice.compression.none, getString(R.string.choice_none) + " (" - + getString(R.string.compression_fast) + ")"), - new Choice(Id.choice.compression.zip, "ZIP (" - + getString(R.string.compression_fast) + ")"), - new Choice(Id.choice.compression.zlib, "ZLIB (" - + getString(R.string.compression_fast) + ")"), - new Choice(Id.choice.compression.bzip2, "BZIP2 (" - + getString(R.string.compression_very_slow) + ")"), - }; - ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(getActivity(), - android.R.layout.simple_spinner_item, choices); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mFileCompression.setAdapter(adapter); - - int defaultFileCompression = Preferences.getPreferences(getActivity()).getDefaultFileCompression(); - for (int i = 0; i < choices.length; ++i) { - if (choices[i].getId() == defaultFileCompression) { - mFileCompression.setSelection(i); - break; - } - } - - mDeleteAfter = (CheckBox) view.findViewById(R.id.deleteAfterEncryption); - mShareAfter = (CheckBox) view.findViewById(R.id.shareAfterEncryption); - - mAsciiArmor = (CheckBox) view.findViewById(R.id.asciiArmor); - mAsciiArmor.setChecked(Preferences.getPreferences(getActivity()).getDefaultAsciiArmor()); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - String filename = getArguments().getString(ARG_FILENAME); - if (filename != null) { - mFilename.setText(filename); - } - boolean asciiArmor = getArguments().getBoolean(ARG_ASCII_ARMOR); - if (asciiArmor) { - mAsciiArmor.setChecked(asciiArmor); - } - } - - /** - * Guess output filename based on input path - * - * @param path - * @return Suggestion for output filename - */ - private String guessOutputFilename(String path) { - // output in the same directory but with additional ending - File file = new File(path); - String ending = (mAsciiArmor.isChecked() ? ".asc" : ".gpg"); - String outputFilename = file.getParent() + File.separator + file.getName() + ending; - - return outputFilename; - } - - private void showOutputFileDialog() { - // Message is received after file is selected - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == FileDialogFragment.MESSAGE_OKAY) { - Bundle data = message.getData(); - mOutputFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME); - encryptStart(); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - mFileDialog = FileDialogFragment.newInstance(messenger, - getString(R.string.title_encrypt_to_file), - getString(R.string.specify_file_to_encrypt_to), mOutputFilename, null); - - mFileDialog.show(getActivity().getSupportFragmentManager(), "fileDialog"); - } - - private void encryptClicked() { - String currentFilename = mFilename.getText().toString(); - if (mInputFilename == null || !mInputFilename.equals(currentFilename)) { - mInputFilename = mFilename.getText().toString(); - } - - mOutputFilename = guessOutputFilename(mInputFilename); - - if (mInputFilename.equals("")) { - AppMsg.makeText(getActivity(), R.string.no_file_selected, AppMsg.STYLE_ALERT).show(); - return; - } - - if (!mInputFilename.startsWith("content")) { - File file = new File(mInputFilename); - if (!file.exists() || !file.isFile()) { - AppMsg.makeText( - getActivity(), - getString(R.string.error_message, - getString(R.string.error_file_not_found)), AppMsg.STYLE_ALERT) - .show(); - return; - } - } - - if (mEncryptInterface.isModeSymmetric()) { - // symmetric encryption - - boolean gotPassphrase = (mEncryptInterface.getPassphrase() != null - && mEncryptInterface.getPassphrase().length() != 0); - if (!gotPassphrase) { - AppMsg.makeText(getActivity(), R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT) - .show(); - return; - } - - if (!mEncryptInterface.getPassphrase().equals(mEncryptInterface.getPassphraseAgain())) { - AppMsg.makeText(getActivity(), R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show(); - return; - } - } else { - // asymmetric encryption - - boolean gotEncryptionKeys = (mEncryptInterface.getEncryptionKeys() != null - && mEncryptInterface.getEncryptionKeys().length > 0); - - if (!gotEncryptionKeys) { - AppMsg.makeText(getActivity(), R.string.select_encryption_key, AppMsg.STYLE_ALERT).show(); - return; - } - - if (!gotEncryptionKeys && mEncryptInterface.getSignatureKey() == 0) { - AppMsg.makeText(getActivity(), R.string.select_encryption_or_signature_key, - AppMsg.STYLE_ALERT).show(); - return; - } - - if (mEncryptInterface.getSignatureKey() != 0 && - PassphraseCacheService.getCachedPassphrase(getActivity(), - mEncryptInterface.getSignatureKey()) == null) { - PassphraseDialogFragment.show(getActivity(), mEncryptInterface.getSignatureKey(), - new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - showOutputFileDialog(); - } - } - }); - - return; - } - } - - showOutputFileDialog(); - } - - private void encryptStart() { - // Send all information needed to service to edit key in other thread - Intent intent = new Intent(getActivity(), KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_ENCRYPT_SIGN); - - // fill values for this action - Bundle data = new Bundle(); - - data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_URI); - - if (mEncryptInterface.isModeSymmetric()) { - Log.d(Constants.TAG, "Symmetric encryption enabled!"); - String passphrase = mEncryptInterface.getPassphrase(); - if (passphrase.length() == 0) { - passphrase = null; - } - data.putString(KeychainIntentService.ENCRYPT_SYMMETRIC_PASSPHRASE, passphrase); - } else { - data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_ID, - mEncryptInterface.getSignatureKey()); - data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS, - mEncryptInterface.getEncryptionKeys()); - } - - Log.d(Constants.TAG, "mInputFilename=" + mInputFilename + ", mOutputFilename=" - + mOutputFilename); - - data.putString(KeychainIntentService.ENCRYPT_INPUT_FILE, mInputFilename); - data.putString(KeychainIntentService.ENCRYPT_OUTPUT_FILE, mOutputFilename); - - boolean useAsciiArmor = mAsciiArmor.isChecked(); - data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, useAsciiArmor); - - int compressionId = ((Choice) mFileCompression.getSelectedItem()).getId(); - data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID, compressionId); -// data.putBoolean(KeychainIntentService.ENCRYPT_GENERATE_SIGNATURE, mGenerateSignature); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after encrypting is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), - getString(R.string.progress_encrypting), ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - AppMsg.makeText(getActivity(), R.string.encryption_successful, - AppMsg.STYLE_INFO).show(); - - if (mDeleteAfter.isChecked()) { - // Create and show dialog to delete original file - DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment - .newInstance(mInputFilename); - deleteFileDialog.show(getActivity().getSupportFragmentManager(), "deleteDialog"); - } - - if (mShareAfter.isChecked()) { - // Share encrypted file - Intent sendFileIntent = new Intent(Intent.ACTION_SEND); - sendFileIntent.setType("*/*"); - sendFileIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(mOutputFilename)); - startActivity(Intent.createChooser(sendFileIntent, - getString(R.string.title_send_file))); - } - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - saveHandler.showProgressDialog(getActivity()); - - // start service with intent - getActivity().startService(intent); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case RESULT_CODE_FILE: { - if (resultCode == Activity.RESULT_OK && data != null) { - try { - String path = FileHelper.getPath(getActivity(), data.getData()); - Log.d(Constants.TAG, "path=" + path); - - mFilename.setText(path); - } catch (NullPointerException e) { - Log.e(Constants.TAG, "Nullpointer while retrieving path!"); - } - } - return; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - - break; - } - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java deleted file mode 100644 index ba11074fc..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptMessageFragment.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.EditText; - -import com.beardedhen.androidbootstrap.BootstrapButton; -import com.devspark.appmsg.AppMsg; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; -import org.sufficientlysecure.keychain.util.Log; - -public class EncryptMessageFragment extends Fragment { - public static final String ARG_TEXT = "text"; - - private EditText mMessage = null; - private BootstrapButton mEncryptShare; - private BootstrapButton mEncryptClipboard; - - private EncryptActivityInterface mEncryptInterface; - - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mEncryptInterface = (EncryptActivityInterface) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface"); - } - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.encrypt_message_fragment, container, false); - - mMessage = (EditText) view.findViewById(R.id.message); - mEncryptClipboard = (BootstrapButton) view.findViewById(R.id.action_encrypt_clipboard); - mEncryptShare = (BootstrapButton) view.findViewById(R.id.action_encrypt_share); - mEncryptClipboard.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - encryptClicked(true); - } - }); - mEncryptShare.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - encryptClicked(false); - } - }); - - return view; - } - - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - String text = getArguments().getString(ARG_TEXT); - if (text != null) { - mMessage.setText(text); - } - } - - /** - * Fixes bad message characters for gmail - * - * @param message - * @return - */ - private String fixBadCharactersForGmail(String message) { - // fix the message a bit, trailing spaces and newlines break stuff, - // because GMail sends as HTML and such things fuck up the - // signature, - // TODO: things like "<" and ">" also fuck up the signature - message = message.replaceAll(" +\n", "\n"); - message = message.replaceAll("\n\n+", "\n\n"); - message = message.replaceFirst("^\n+", ""); - // make sure there'll be exactly one newline at the end - message = message.replaceFirst("\n*$", "\n"); - - return message; - } - - private void encryptClicked(final boolean toClipboard) { - if (mEncryptInterface.isModeSymmetric()) { - // symmetric encryption - - boolean gotPassphrase = (mEncryptInterface.getPassphrase() != null - && mEncryptInterface.getPassphrase().length() != 0); - if (!gotPassphrase) { - AppMsg.makeText(getActivity(), R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT) - .show(); - return; - } - - if (!mEncryptInterface.getPassphrase().equals(mEncryptInterface.getPassphraseAgain())) { - AppMsg.makeText(getActivity(), R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show(); - return; - } - - } else { - // asymmetric encryption - - boolean gotEncryptionKeys = (mEncryptInterface.getEncryptionKeys() != null - && mEncryptInterface.getEncryptionKeys().length > 0); - - if (!gotEncryptionKeys && mEncryptInterface.getSignatureKey() == 0) { - AppMsg.makeText(getActivity(), R.string.select_encryption_or_signature_key, - AppMsg.STYLE_ALERT).show(); - return; - } - - if (mEncryptInterface.getSignatureKey() != 0 && - PassphraseCacheService.getCachedPassphrase(getActivity(), - mEncryptInterface.getSignatureKey()) == null) { - PassphraseDialogFragment.show(getActivity(), mEncryptInterface.getSignatureKey(), - new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - encryptStart(toClipboard); - } - } - }); - - return; - } - } - - encryptStart(toClipboard); - } - - private void encryptStart(final boolean toClipboard) { - // Send all information needed to service to edit key in other thread - Intent intent = new Intent(getActivity(), KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_ENCRYPT_SIGN); - - // fill values for this action - Bundle data = new Bundle(); - - data.putInt(KeychainIntentService.TARGET, KeychainIntentService.TARGET_BYTES); - - String message = mMessage.getText().toString(); - - if (mEncryptInterface.isModeSymmetric()) { - Log.d(Constants.TAG, "Symmetric encryption enabled!"); - String passphrase = mEncryptInterface.getPassphrase(); - if (passphrase.length() == 0) { - passphrase = null; - } - data.putString(KeychainIntentService.ENCRYPT_SYMMETRIC_PASSPHRASE, passphrase); - } else { - data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_ID, - mEncryptInterface.getSignatureKey()); - data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS, - mEncryptInterface.getEncryptionKeys()); - - boolean signOnly = (mEncryptInterface.getEncryptionKeys() == null - || mEncryptInterface.getEncryptionKeys().length == 0); - if (signOnly) { - message = fixBadCharactersForGmail(message); - } - } - - data.putByteArray(KeychainIntentService.ENCRYPT_MESSAGE_BYTES, message.getBytes()); - - data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, true); - - int compressionId = Preferences.getPreferences(getActivity()).getDefaultMessageCompression(); - data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID, compressionId); -// data.putBoolean(KeychainIntentService.ENCRYPT_GENERATE_SIGNATURE, mGenerateSignature); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after encrypting is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), - getString(R.string.progress_encrypting), ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get returned data bundle - Bundle data = message.getData(); - - String output = new String(data.getByteArray(KeychainIntentService.RESULT_BYTES)); - Log.d(Constants.TAG, "output: " + output); - - if (toClipboard) { - ClipboardReflection.copyToClipboard(getActivity(), output); - AppMsg.makeText(getActivity(), - R.string.encryption_to_clipboard_successful, AppMsg.STYLE_INFO) - .show(); - } else { - Intent sendIntent = new Intent(Intent.ACTION_SEND); - - // Type is set to text/plain so that encrypted messages can - // be sent with Whatsapp, Hangouts, SMS etc... - sendIntent.setType("text/plain"); - - sendIntent.putExtra(Intent.EXTRA_TEXT, output); - startActivity(Intent.createChooser(sendIntent, - getString(R.string.title_send_email))); - } - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - saveHandler.showProgressDialog(getActivity()); - - // start service with intent - getActivity().startService(intent); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java deleted file mode 100644 index 8efa07953..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptSymmetricFragment.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.EditText; - -import org.sufficientlysecure.keychain.R; - -public class EncryptSymmetricFragment extends Fragment { - - OnSymmetricKeySelection mPassphraseUpdateListener; - - private EditText mPassphrase; - private EditText mPassphraseAgain; - - // Container Activity must implement this interface - public interface OnSymmetricKeySelection { - public void onPassphraseUpdate(String passphrase); - - public void onPassphraseAgainUpdate(String passphrase); - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mPassphraseUpdateListener = (OnSymmetricKeySelection) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement OnSymmetricKeySelection"); - } - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.encrypt_symmetric_fragment, container, false); - - mPassphrase = (EditText) view.findViewById(R.id.passphrase); - mPassphraseAgain = (EditText) view.findViewById(R.id.passphraseAgain); - mPassphrase.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 passphrase in EncryptActivity - mPassphraseUpdateListener.onPassphraseUpdate(s.toString()); - } - }); - mPassphraseAgain.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 passphrase in EncryptActivity - mPassphraseUpdateListener.onPassphraseAgainUpdate(s.toString()); - } - }); - - return view; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java deleted file mode 100644 index a484b57de..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpAboutFragment.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import org.sufficientlysecure.htmltextview.HtmlTextView; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Log; - - -public class HelpAboutFragment extends Fragment { - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.help_about_fragment, container, false); - - TextView versionText = (TextView) view.findViewById(R.id.help_about_version); - versionText.setText(getString(R.string.help_about_version) + " " + getVersion()); - - HtmlTextView aboutTextView = (HtmlTextView) view.findViewById(R.id.help_about_text); - - // load html from raw resource (Parsing handled by HtmlTextView library) - aboutTextView.setHtmlFromRawResource(getActivity(), R.raw.help_about); - - // no flickering when clicking textview for Android < 4 - aboutTextView.setTextColor(getResources().getColor(android.R.color.black)); - - return view; - } - - /** - * Get the current package version. - * - * @return The current version. - */ - private String getVersion() { - String result = ""; - try { - PackageManager manager = getActivity().getPackageManager(); - PackageInfo info = manager.getPackageInfo(getActivity().getPackageName(), 0); - - result = String.format("%s (%s)", info.versionName, info.versionCode); - } catch (NameNotFoundException e) { - Log.w(Constants.TAG, "Unable to get application version: " + e.getMessage()); - result = "Unable to get application version."; - } - - return result; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java deleted file mode 100644 index 32f37a0a5..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.view.ViewPager; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter; - -public class HelpActivity extends ActionBarActivity { - public static final String EXTRA_SELECTED_TAB = "selected_tab"; - - ViewPager mViewPager; - TabsAdapter mTabsAdapter; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.help_activity); - - mViewPager = (ViewPager) findViewById(R.id.pager); - - final ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(false); - actionBar.setHomeButtonEnabled(false); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - - mTabsAdapter = new TabsAdapter(this, mViewPager); - - int selectedTab = 0; - Intent intent = getIntent(); - if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) { - selectedTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB); - } - - Bundle startBundle = new Bundle(); - startBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_start); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_start)), - HelpHtmlFragment.class, startBundle, (selectedTab == 0)); - - Bundle faqBundle = new Bundle(); - faqBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_faq); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_faq)), - HelpHtmlFragment.class, faqBundle, (selectedTab == 1)); - - Bundle nfcBundle = new Bundle(); - nfcBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_nfc_beam); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_nfc_beam)), - HelpHtmlFragment.class, nfcBundle, (selectedTab == 2)); - - Bundle changelogBundle = new Bundle(); - changelogBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_changelog); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_changelog)), - HelpHtmlFragment.class, changelogBundle, (selectedTab == 3)); - - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_about)), - HelpAboutFragment.class, null, (selectedTab == 4)); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java deleted file mode 100644 index 6b3c51b08..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpHtmlFragment.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.util.TypedValue; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ScrollView; -import org.sufficientlysecure.htmltextview.HtmlTextView; - -public class HelpHtmlFragment extends Fragment { - private Activity mActivity; - - private int mHtmlFile; - - public static final String ARG_HTML_FILE = "htmlFile"; - - /** - * Create a new instance of HelpHtmlFragment, providing "htmlFile" as an argument. - */ - static HelpHtmlFragment newInstance(int htmlFile) { - HelpHtmlFragment f = new HelpHtmlFragment(); - - // Supply html raw file input as an argument. - Bundle args = new Bundle(); - args.putInt(ARG_HTML_FILE, htmlFile); - f.setArguments(args); - - return f; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - mActivity = getActivity(); - - mHtmlFile = getArguments().getInt(ARG_HTML_FILE); - - ScrollView scroller = new ScrollView(mActivity); - HtmlTextView text = new HtmlTextView(mActivity); - - // padding - int padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, mActivity - .getResources().getDisplayMetrics()); - text.setPadding(padding, padding, padding, 0); - - scroller.addView(text); - - // load html from raw resource (Parsing handled by HtmlTextView library) - text.setHtmlFromRawResource(getActivity(), mHtmlFile); - - // no flickering when clicking textview for Android < 4 - text.setTextColor(getResources().getColor(android.R.color.black)); - - return scroller; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java deleted file mode 100644 index 6ea79473a..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2011 Senecaso - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.nfc.NdefMessage; -import android.nfc.NfcAdapter; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.os.Parcelable; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ArrayAdapter; - -import com.beardedhen.androidbootstrap.BootstrapButton; -import com.devspark.appmsg.AppMsg; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; -import org.sufficientlysecure.keychain.ui.dialog.BadImportKeyDialogFragment; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; -import java.util.Locale; - -public class ImportKeysActivity extends ActionBarActivity implements ActionBar.OnNavigationListener { - public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY"; - public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX - + "IMPORT_KEY_FROM_QR_CODE"; - public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = Constants.INTENT_PREFIX - + "IMPORT_KEY_FROM_KEYSERVER"; - public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN = Constants.INTENT_PREFIX - + "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN"; - - // Actions for internal use only: - public static final String ACTION_IMPORT_KEY_FROM_FILE = Constants.INTENT_PREFIX - + "IMPORT_KEY_FROM_FILE"; - public static final String ACTION_IMPORT_KEY_FROM_NFC = Constants.INTENT_PREFIX - + "IMPORT_KEY_FROM_NFC"; - - // only used by ACTION_IMPORT_KEY - public static final String EXTRA_KEY_BYTES = "key_bytes"; - - // only used by ACTION_IMPORT_KEY_FROM_KEYSERVER - public static final String EXTRA_QUERY = "query"; - public static final String EXTRA_KEY_ID = "key_id"; - public static final String EXTRA_FINGERPRINT = "fingerprint"; - - // only used by ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN when used from OpenPgpService - public static final String EXTRA_PENDING_INTENT_DATA = "data"; - private Intent mPendingIntentData; - - // view - private ImportKeysListFragment mListFragment; - private String[] mNavigationStrings; - private Fragment mCurrentFragment; - private BootstrapButton mImportButton; - - private static final Class[] NAVIGATION_CLASSES = new Class[]{ - ImportKeysServerFragment.class, - ImportKeysFileFragment.class, - ImportKeysQrCodeFragment.class, - ImportKeysClipboardFragment.class, - ImportKeysNFCFragment.class - }; - - private int mCurrentNavPosition = -1; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.import_keys_activity); - - mImportButton = (BootstrapButton) findViewById(R.id.import_import); - mImportButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - importKeys(); - } - }); - - mNavigationStrings = getResources().getStringArray(R.array.import_action_list); - - if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN.equals(getIntent().getAction())) { - setTitle(R.string.nav_import); - } else { - ActionBarHelper.setBackButton(this); - getSupportActionBar().setDisplayShowTitleEnabled(false); - - // set drop down navigation - Context context = getSupportActionBar().getThemedContext(); - ArrayAdapter<CharSequence> navigationAdapter = ArrayAdapter.createFromResource(context, - R.array.import_action_list, android.R.layout.simple_spinner_dropdown_item); - getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); - getSupportActionBar().setListNavigationCallbacks(navigationAdapter, this); - } - - handleActions(savedInstanceState, getIntent()); - } - - protected void handleActions(Bundle savedInstanceState, Intent intent) { - String action = intent.getAction(); - Bundle extras = intent.getExtras(); - Uri dataUri = intent.getData(); - String scheme = intent.getScheme(); - - if (extras == null) { - extras = new Bundle(); - } - - if (Intent.ACTION_VIEW.equals(action)) { - // Android's Action when opening file associated to Keychain (see AndroidManifest.xml) - // override action to delegate it to Keychain's ACTION_IMPORT_KEY - action = ACTION_IMPORT_KEY; - } - - if (scheme != null && scheme.toLowerCase(Locale.ENGLISH).equals(Constants.FINGERPRINT_SCHEME)) { - /* Scanning a fingerprint directly with Barcode Scanner */ - loadFromFingerprintUri(savedInstanceState, dataUri); - } else if (ACTION_IMPORT_KEY.equals(action)) { - /* Keychain's own Actions */ - - // display file fragment - loadNavFragment(1, null); - - if (dataUri != null) { - // action: directly load data - startListFragment(savedInstanceState, null, dataUri, null); - } else if (extras.containsKey(EXTRA_KEY_BYTES)) { - byte[] importData = intent.getByteArrayExtra(EXTRA_KEY_BYTES); - - // action: directly load data - startListFragment(savedInstanceState, importData, null, null); - } - } else if (ACTION_IMPORT_KEY_FROM_KEYSERVER.equals(action) - || ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN.equals(action)) { - - // only used for OpenPgpService - if (extras.containsKey(EXTRA_PENDING_INTENT_DATA)) { - mPendingIntentData = extras.getParcelable(EXTRA_PENDING_INTENT_DATA); - } - if (extras.containsKey(EXTRA_QUERY) || extras.containsKey(EXTRA_KEY_ID)) { - /* simple search based on query or key id */ - - String query = null; - if (extras.containsKey(EXTRA_QUERY)) { - query = extras.getString(EXTRA_QUERY); - } else if (extras.containsKey(EXTRA_KEY_ID)) { - long keyId = intent.getLongExtra(EXTRA_KEY_ID, 0); - if (keyId != 0) { - query = PgpKeyHelper.convertKeyIdToHex(keyId); - } - } - - if (query != null && query.length() > 0) { - // display keyserver fragment with query - Bundle args = new Bundle(); - args.putString(ImportKeysServerFragment.ARG_QUERY, query); - loadNavFragment(0, args); - - // action: search immediately - startListFragment(savedInstanceState, null, null, query); - } else { - Log.e(Constants.TAG, "Query is empty!"); - return; - } - } else if (extras.containsKey(EXTRA_FINGERPRINT)) { - /* - * search based on fingerprint, here we can enforce a check in the end - * if the right key has been downloaded - */ - - String fingerprint = intent.getStringExtra(EXTRA_FINGERPRINT); - loadFromFingerprint(savedInstanceState, fingerprint); - } else { - Log.e(Constants.TAG, - "IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query', 'key_id', or " + - "'fingerprint' extra!"); - return; - } - } else if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) { - - // NOTE: this only displays the appropriate fragment, no actions are taken - loadNavFragment(1, null); - - // no immediate actions! - startListFragment(savedInstanceState, null, null, null); - } else if (ACTION_IMPORT_KEY_FROM_QR_CODE.equals(action)) { - // also exposed in AndroidManifest - - // NOTE: this only displays the appropriate fragment, no actions are taken - loadNavFragment(2, null); - - // no immediate actions! - startListFragment(savedInstanceState, null, null, null); - } else if (ACTION_IMPORT_KEY_FROM_NFC.equals(action)) { - - // NOTE: this only displays the appropriate fragment, no actions are taken - loadNavFragment(3, null); - - // no immediate actions! - startListFragment(savedInstanceState, null, null, null); - } else { - startListFragment(savedInstanceState, null, null, null); - } - } - - private void startListFragment(Bundle savedInstanceState, byte[] bytes, Uri dataUri, String serverQuery) { - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; - } - - // Create an instance of the fragment - mListFragment = ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery); - - // Add the fragment to the 'fragment_container' FrameLayout - // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! - getSupportFragmentManager().beginTransaction() - .replace(R.id.import_keys_list_container, mListFragment) - .commitAllowingStateLoss(); - // do it immediately! - getSupportFragmentManager().executePendingTransactions(); - } - - /** - * "Basically, when using a list navigation, onNavigationItemSelected() is automatically - * called when your activity is created/re-created, whether you like it or not. To prevent - * your Fragment's onCreateView() from being called twice, this initial automatic call to - * onNavigationItemSelected() should check whether the Fragment is already in existence - * inside your Activity." - * <p/> - * from http://stackoverflow.com/a/14295474 - * <p/> - * In our case, if we start ImportKeysActivity with parameters to directly search using a fingerprint, - * the fragment would be loaded twice resulting in the query being empty after the second load. - * <p/> - * Our solution: - * To prevent that a fragment will be loaded again even if it was already loaded loadNavFragment - * checks against mCurrentNavPosition. - * - * @param itemPosition - * @param itemId - * @return - */ - @Override - public boolean onNavigationItemSelected(int itemPosition, long itemId) { - Log.d(Constants.TAG, "onNavigationItemSelected"); - - loadNavFragment(itemPosition, null); - - return true; - } - - private void loadNavFragment(int itemPosition, Bundle args) { - if (mCurrentNavPosition != itemPosition) { - if (ActionBar.NAVIGATION_MODE_LIST == getSupportActionBar().getNavigationMode()) { - getSupportActionBar().setSelectedNavigationItem(itemPosition); - } - loadFragment(NAVIGATION_CLASSES[itemPosition], args, mNavigationStrings[itemPosition]); - mCurrentNavPosition = itemPosition; - } - } - - private void loadFragment(Class<?> clss, Bundle args, String tag) { - mCurrentFragment = Fragment.instantiate(this, clss.getName(), args); - - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - // Replace whatever is in the fragment container with this fragment - // and give the fragment a tag name equal to the string at the position selected - ft.replace(R.id.import_navigation_fragment, mCurrentFragment, tag); - // Apply changes - ft.commit(); - } - - public void loadFromFingerprintUri(Bundle savedInstanceState, Uri dataUri) { - String fingerprint = dataUri.toString().split(":")[1].toLowerCase(Locale.ENGLISH); - - Log.d(Constants.TAG, "fingerprint: " + fingerprint); - - loadFromFingerprint(savedInstanceState, fingerprint); - } - - public void loadFromFingerprint(Bundle savedInstanceState, String fingerprint) { - if (fingerprint == null || fingerprint.length() < 40) { - AppMsg.makeText(this, R.string.import_qr_code_too_short_fingerprint, - AppMsg.STYLE_ALERT).show(); - return; - } - - String query = "0x" + fingerprint; - - // display keyserver fragment with query - Bundle args = new Bundle(); - args.putString(ImportKeysServerFragment.ARG_QUERY, query); - args.putBoolean(ImportKeysServerFragment.ARG_DISABLE_QUERY_EDIT, true); - loadNavFragment(0, args); - - // action: search directly - startListFragment(savedInstanceState, null, null, query); - } - - public void loadCallback(byte[] importData, Uri dataUri, String serverQuery, String keyServer) { - mListFragment.loadNew(importData, dataUri, serverQuery, keyServer); - } - - /** - * Import keys with mImportData - */ - public void importKeys() { - // 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); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get returned data bundle - Bundle returnData = message.getData(); - - int added = returnData.getInt(KeychainIntentService.RESULT_IMPORT_ADDED); - int updated = returnData - .getInt(KeychainIntentService.RESULT_IMPORT_UPDATED); - int bad = returnData.getInt(KeychainIntentService.RESULT_IMPORT_BAD); - String toastMessage; - if (added > 0 && updated > 0) { - String addedStr = getResources().getQuantityString( - R.plurals.keys_added_and_updated_1, added, added); - String updatedStr = getResources().getQuantityString( - R.plurals.keys_added_and_updated_2, updated, updated); - toastMessage = addedStr + updatedStr; - } else if (added > 0) { - toastMessage = getResources().getQuantityString(R.plurals.keys_added, - added, added); - } else if (updated > 0) { - toastMessage = getResources().getQuantityString(R.plurals.keys_updated, - updated, updated); - } else { - toastMessage = getString(R.string.no_keys_added_or_updated); - } - AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO) - .show(); - if (bad > 0) { - BadImportKeyDialogFragment badImportKeyDialogFragment = - BadImportKeyDialogFragment.newInstance(bad); - badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog"); - } - - if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN.equals(getIntent().getAction())) { - ImportKeysActivity.this.setResult(Activity.RESULT_OK, mPendingIntentData); - finish(); - } - } - } - }; - - if (mListFragment.getKeyBytes() != null || mListFragment.getDataUri() != null) { - Log.d(Constants.TAG, "importKeys started"); - - // Send all information needed to service to import key in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING); - - // fill values for this action - Bundle data = new Bundle(); - - // get selected key entries - ArrayList<ImportKeysListEntry> selectedEntries = mListFragment.getSelectedData(); - data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, selectedEntries); - - 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); - - // show progress dialog - saveHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } else if (mListFragment.getServerQuery() != null) { - // Send all information needed to service to query keys in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_DOWNLOAD_AND_IMPORT_KEYS); - - // fill values for this action - Bundle data = new Bundle(); - - data.putString(KeychainIntentService.DOWNLOAD_KEY_SERVER, mListFragment.getKeyServer()); - - // get selected key entries - ArrayList<ImportKeysListEntry> selectedEntries = mListFragment.getSelectedData(); - data.putParcelableArrayList(KeychainIntentService.DOWNLOAD_KEY_LIST, selectedEntries); - - 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); - - // show progress dialog - saveHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } else { - AppMsg.makeText(this, R.string.error_nothing_import, AppMsg.STYLE_ALERT).show(); - } - } - - /** - * NFC - */ - @Override - public void onResume() { - super.onResume(); - // Check to see that the Activity started due to an Android Beam - if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { - handleActionNdefDiscovered(getIntent()); - } - } - - /** - * NFC - */ - @Override - public void onNewIntent(Intent intent) { - // onResume gets called after this to handle the intent - setIntent(intent); - } - - /** - * NFC: Parses the NDEF Message from the intent and prints to the TextView - */ - @SuppressLint("NewApi") - void handleActionNdefDiscovered(Intent intent) { - Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); - // only one message sent during the beam - NdefMessage msg = (NdefMessage) rawMsgs[0]; - // record 0 contains the MIME type, record 1 is the AAR, if present - byte[] receivedKeyringBytes = msg.getRecords()[0].getPayload(); - - Intent importIntent = new Intent(this, ImportKeysActivity.class); - importIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY); - importIntent.putExtra(ImportKeysActivity.EXTRA_KEY_BYTES, receivedKeyringBytes); - - handleActions(null, importIntent); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java deleted file mode 100644 index 28e2091a9..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysClipboardFragment.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import com.beardedhen.androidbootstrap.BootstrapButton; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; - -import java.util.Locale; - -public class ImportKeysClipboardFragment extends Fragment { - - private ImportKeysActivity mImportActivity; - private BootstrapButton mButton; - - /** - * Creates new instance of this fragment - */ - public static ImportKeysClipboardFragment newInstance() { - ImportKeysClipboardFragment frag = new ImportKeysClipboardFragment(); - - Bundle args = new Bundle(); - frag.setArguments(args); - - return frag; - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.import_keys_clipboard_fragment, container, false); - - mButton = (BootstrapButton) view.findViewById(R.id.import_clipboard_button); - mButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity()); - String sendText = ""; - if (clipboardText != null) { - sendText = clipboardText.toString(); - if (sendText.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) { - mImportActivity.loadFromFingerprintUri(null, Uri.parse(sendText)); - return; - } - } - mImportActivity.loadCallback(sendText.getBytes(), null, null, null); - } - }); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mImportActivity = (ImportKeysActivity) getActivity(); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java deleted file mode 100644 index 31d5f3fd0..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import com.beardedhen.androidbootstrap.BootstrapButton; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.FileHelper; - -public class ImportKeysFileFragment extends Fragment { - private ImportKeysActivity mImportActivity; - private BootstrapButton mBrowse; - - /** - * Creates new instance of this fragment - */ - public static ImportKeysFileFragment newInstance() { - ImportKeysFileFragment frag = new ImportKeysFileFragment(); - - Bundle args = new Bundle(); - - frag.setArguments(args); - return frag; - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.import_keys_file_fragment, container, false); - - mBrowse = (BootstrapButton) view.findViewById(R.id.import_keys_file_browse); - - mBrowse.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - // open .asc or .gpg files - // setting it to text/plain prevents Cynaogenmod's file manager from selecting asc - // or gpg types! - FileHelper.openFile(ImportKeysFileFragment.this, Constants.Path.APP_DIR + "/", - "*/*", Id.request.filename); - } - }); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mImportActivity = (ImportKeysActivity) getActivity(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode & 0xFFFF) { - case Id.request.filename: { - if (resultCode == Activity.RESULT_OK && data != null) { - - // load data - mImportActivity.loadCallback(null, data.getData(), null, null); - } - - break; - } - - default: - super.onActivityResult(requestCode, resultCode, data); - - break; - } - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java deleted file mode 100644 index 077fa0cab..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.ListFragment; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; -import android.view.View; -import android.widget.ListView; -import com.devspark.appmsg.AppMsg; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.KeyServer; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.ByteArrayInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -public class ImportKeysListFragment extends ListFragment implements - LoaderManager.LoaderCallbacks<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { - private static final String ARG_DATA_URI = "uri"; - private static final String ARG_BYTES = "bytes"; - private static final String ARG_SERVER_QUERY = "query"; - - private Activity mActivity; - private ImportKeysAdapter mAdapter; - - private byte[] mKeyBytes; - private Uri mDataUri; - private String mServerQuery; - private String mKeyServer; - - private static final int LOADER_ID_BYTES = 0; - private static final int LOADER_ID_SERVER_QUERY = 1; - - public byte[] getKeyBytes() { - return mKeyBytes; - } - - public Uri getDataUri() { - return mDataUri; - } - - public String getServerQuery() { - return mServerQuery; - } - - public String getKeyServer() { - return mKeyServer; - } - - public List<ImportKeysListEntry> getData() { - return mAdapter.getData(); - } - - public ArrayList<ImportKeysListEntry> getSelectedData() { - return mAdapter.getSelectedData(); - } - - /** - * Creates new instance of this fragment - */ - public static ImportKeysListFragment newInstance(byte[] bytes, Uri dataUri, String serverQuery) { - ImportKeysListFragment frag = new ImportKeysListFragment(); - - Bundle args = new Bundle(); - args.putByteArray(ARG_BYTES, bytes); - args.putParcelable(ARG_DATA_URI, dataUri); - args.putString(ARG_SERVER_QUERY, serverQuery); - - frag.setArguments(args); - - return frag; - } - - /** - * Define Adapter and Loader on create of Activity - */ - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mActivity = getActivity(); - - // Give some text to display if there is no data. In a real - // application this would come from a resource. - setEmptyText(mActivity.getString(R.string.error_nothing_import)); - - // Create an empty adapter we will use to display the loaded data. - mAdapter = new ImportKeysAdapter(mActivity); - setListAdapter(mAdapter); - - mDataUri = getArguments().getParcelable(ARG_DATA_URI); - mKeyBytes = getArguments().getByteArray(ARG_BYTES); - mServerQuery = getArguments().getString(ARG_SERVER_QUERY); - - // TODO: this is used when scanning QR Code. Currently it simply uses keyserver nr 0 - mKeyServer = Preferences.getPreferences(getActivity()) - .getKeyServers()[0]; - - if (mDataUri != null || mKeyBytes != null) { - // Start out with a progress indicator. - setListShown(false); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - // give arguments to onCreateLoader() - getLoaderManager().initLoader(LOADER_ID_BYTES, null, this); - } - - if (mServerQuery != null && mKeyServer != null) { - // Start out with a progress indicator. - setListShown(false); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - // give arguments to onCreateLoader() - getLoaderManager().initLoader(LOADER_ID_SERVER_QUERY, null, this); - } - } - - @Override - public void onListItemClick(ListView l, View v, int position, long id) { - super.onListItemClick(l, v, position, id); - - // Select checkbox! - // Update underlying data and notify adapter of change. The adapter will - // update the view automatically. - ImportKeysListEntry entry = mAdapter.getItem(position); - entry.setSelected(!entry.isSelected()); - mAdapter.notifyDataSetChanged(); - } - - public void loadNew(byte[] keyBytes, Uri dataUri, String serverQuery, String keyServer) { - mKeyBytes = keyBytes; - mDataUri = dataUri; - mServerQuery = serverQuery; - mKeyServer = keyServer; - - if (mKeyBytes != null || mDataUri != null) { - // Start out with a progress indicator. - setListShown(false); - - getLoaderManager().restartLoader(LOADER_ID_BYTES, null, this); - } - - if (mServerQuery != null && mKeyServer != null) { - // Start out with a progress indicator. - setListShown(false); - - getLoaderManager().restartLoader(LOADER_ID_SERVER_QUERY, null, this); - } - } - - @Override - public Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> - onCreateLoader(int id, Bundle args) { - switch (id) { - case LOADER_ID_BYTES: { - InputData inputData = getInputData(mKeyBytes, mDataUri); - return new ImportKeysListLoader(mActivity, inputData); - } - case LOADER_ID_SERVER_QUERY: { - return new ImportKeysListServerLoader(getActivity(), mServerQuery, mKeyServer); - } - - default: - return null; - } - } - - @Override - public void onLoadFinished(Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> loader, - AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) { - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - - Log.d(Constants.TAG, "data: " + data.getResult()); - - // swap in the real data! - mAdapter.setData(data.getResult()); - mAdapter.notifyDataSetChanged(); - - setListAdapter(mAdapter); - - // The list should now be shown. - if (isResumed()) { - setListShown(true); - } else { - setListShownNoAnimation(true); - } - - Exception error = data.getError(); - - switch (loader.getId()) { - case LOADER_ID_BYTES: - - if (error == null) { - // No error - } else if (error instanceof ImportKeysListLoader.FileHasNoContent) { - AppMsg.makeText(getActivity(), R.string.error_import_file_no_content, - AppMsg.STYLE_ALERT).show(); - } else if (error instanceof ImportKeysListLoader.NonPgpPart) { - AppMsg.makeText(getActivity(), - ((ImportKeysListLoader.NonPgpPart) error).getCount() + " " + getResources(). - getQuantityString(R.plurals.error_import_non_pgp_part, - ((ImportKeysListLoader.NonPgpPart) error).getCount()), - new AppMsg.Style(AppMsg.LENGTH_LONG, R.color.confirm)).show(); - } else { - AppMsg.makeText(getActivity(), R.string.error_generic_report_bug, - new AppMsg.Style(AppMsg.LENGTH_LONG, R.color.alert)).show(); - } - break; - - case LOADER_ID_SERVER_QUERY: - - if (error == null) { - AppMsg.makeText( - getActivity(), getResources().getQuantityString(R.plurals.keys_found, - mAdapter.getCount(), mAdapter.getCount()), - AppMsg.STYLE_INFO - ).show(); - } else if (error instanceof KeyServer.InsufficientQuery) { - AppMsg.makeText(getActivity(), R.string.error_keyserver_insufficient_query, - AppMsg.STYLE_ALERT).show(); - } else if (error instanceof KeyServer.QueryException) { - AppMsg.makeText(getActivity(), R.string.error_keyserver_query, - AppMsg.STYLE_ALERT).show(); - } else if (error instanceof KeyServer.TooManyResponses) { - AppMsg.makeText(getActivity(), R.string.error_keyserver_too_many_responses, - AppMsg.STYLE_ALERT).show(); - } - break; - - default: - break; - } - } - - @Override - public void onLoaderReset(Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> loader) { - switch (loader.getId()) { - case LOADER_ID_BYTES: - // Clear the data in the adapter. - mAdapter.clear(); - break; - case LOADER_ID_SERVER_QUERY: - // Clear the data in the adapter. - mAdapter.clear(); - break; - default: - break; - } - } - - private InputData getInputData(byte[] importBytes, Uri dataUri) { - InputData inputData = null; - if (importBytes != null) { - inputData = new InputData(new ByteArrayInputStream(importBytes), importBytes.length); - } else if (dataUri != null) { - try { - InputStream inputStream = getActivity().getContentResolver().openInputStream(dataUri); - int length = inputStream.available(); - - inputData = new InputData(inputStream, length); - } catch (FileNotFoundException e) { - Log.e(Constants.TAG, "FileNotFoundException!", e); - } catch (IOException e) { - Log.e(Constants.TAG, "IOException!", e); - } - } - - return inputData; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java deleted file mode 100644 index 110647284..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysNFCFragment.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import com.beardedhen.androidbootstrap.BootstrapButton; -import org.sufficientlysecure.keychain.R; - -public class ImportKeysNFCFragment extends Fragment { - - private BootstrapButton mButton; - - /** - * Creates new instance of this fragment - */ - public static ImportKeysNFCFragment newInstance() { - ImportKeysNFCFragment frag = new ImportKeysNFCFragment(); - - Bundle args = new Bundle(); - frag.setArguments(args); - - return frag; - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.import_keys_nfc_fragment, container, false); - - mButton = (BootstrapButton) view.findViewById(R.id.import_nfc_button); - mButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - // show nfc help - Intent intent = new Intent(getActivity(), HelpActivity.class); - intent.putExtra(HelpActivity.EXTRA_SELECTED_TAB, 2); - startActivityForResult(intent, 0); - } - }); - - return view; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java deleted file mode 100644 index 8b553d273..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysQrCodeFragment.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import com.google.zxing.integration.android.IntentResult; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; - -import com.beardedhen.androidbootstrap.BootstrapButton; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; -import java.util.Locale; - -public class ImportKeysQrCodeFragment extends Fragment { - - private ImportKeysActivity mImportActivity; - private BootstrapButton mButton; - private TextView mText; - private ProgressBar mProgress; - - private String[] mScannedContent; - - /** - * Creates new instance of this fragment - */ - public static ImportKeysQrCodeFragment newInstance() { - ImportKeysQrCodeFragment frag = new ImportKeysQrCodeFragment(); - - Bundle args = new Bundle(); - frag.setArguments(args); - - return frag; - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.import_keys_qr_code_fragment, container, false); - - mButton = (BootstrapButton) view.findViewById(R.id.import_qrcode_button); - mText = (TextView) view.findViewById(R.id.import_qrcode_text); - mProgress = (ProgressBar) view.findViewById(R.id.import_qrcode_progress); - - mButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - // scan using xzing's Barcode Scanner - new IntentIntegratorSupportV4(ImportKeysQrCodeFragment.this).initiateScan(); - } - }); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mImportActivity = (ImportKeysActivity) getActivity(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode & 0xFFFF) { - case IntentIntegratorSupportV4.REQUEST_CODE: { - IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode, - resultCode, data); - if (scanResult != null && scanResult.getFormatName() != null) { - String scannedContent = scanResult.getContents(); - - Log.d(Constants.TAG, "scannedContent: " + scannedContent); - - // look if it's fingerprint only - if (scannedContent.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) { - importFingerprint(Uri.parse(scanResult.getContents())); - return; - } - - // look if it is the whole key - String[] parts = scannedContent.split(","); - if (parts.length == 3) { - importParts(parts); - return; - } - - // is this a full key encoded as qr code? - if (scannedContent.startsWith("-----BEGIN PGP")) { - mImportActivity.loadCallback(scannedContent.getBytes(), null, null, null); - return; - } - - // fail... - Toast.makeText(getActivity(), R.string.import_qr_code_wrong, Toast.LENGTH_LONG) - .show(); - } - - break; - } - - default: - super.onActivityResult(requestCode, resultCode, data); - - break; - } - } - - public void importFingerprint(Uri dataUri) { - mImportActivity.loadFromFingerprintUri(null, dataUri); - } - - private void importParts(String[] parts) { - int counter = Integer.valueOf(parts[0]); - int size = Integer.valueOf(parts[1]); - String content = parts[2]; - - Log.d(Constants.TAG, "" + counter); - Log.d(Constants.TAG, "" + size); - Log.d(Constants.TAG, "" + content); - - // first qr code -> setup - if (counter == 0) { - mScannedContent = new String[size]; - mProgress.setMax(size); - mProgress.setVisibility(View.VISIBLE); - mText.setVisibility(View.VISIBLE); - } - - if (mScannedContent == null || counter > mScannedContent.length) { - Toast.makeText(getActivity(), R.string.import_qr_code_start_with_one, Toast.LENGTH_LONG) - .show(); - return; - } - - // save scanned content - mScannedContent[counter] = content; - - // get missing numbers - ArrayList<Integer> missing = new ArrayList<Integer>(); - for (int i = 0; i < mScannedContent.length; i++) { - if (mScannedContent[i] == null) { - missing.add(i); - } - } - - // update progress and text - int alreadyScanned = mScannedContent.length - missing.size(); - mProgress.setProgress(alreadyScanned); - - String missingString = ""; - for (int m : missing) { - if (!missingString.equals("")) { - missingString += ", "; - } - missingString += String.valueOf(m + 1); - } - - String missingText = getResources().getQuantityString(R.plurals.import_qr_code_missing, - missing.size(), missingString); - mText.setText(missingText); - - // finished! - if (missing.size() == 0) { - mText.setText(R.string.import_qr_code_finished); - String result = ""; - for (String in : mScannedContent) { - result += in; - } - mImportActivity.loadCallback(result.getBytes(), null, null, null); - } - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java deleted file mode 100644 index 3eb463dac..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysServerFragment.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Context; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.TextView; -import com.beardedhen.androidbootstrap.BootstrapButton; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.util.Log; - -public class ImportKeysServerFragment extends Fragment { - public static final String ARG_QUERY = "query"; - public static final String ARG_KEY_SERVER = "key_server"; - public static final String ARG_DISABLE_QUERY_EDIT = "disable_query_edit"; - - private ImportKeysActivity mImportActivity; - - private BootstrapButton mSearchButton; - private EditText mQueryEditText; - private Spinner mServerSpinner; - private ArrayAdapter<String> mServerAdapter; - - /** - * Creates new instance of this fragment - */ - public static ImportKeysServerFragment newInstance(String query, String keyServer) { - ImportKeysServerFragment frag = new ImportKeysServerFragment(); - - Bundle args = new Bundle(); - args.putString(ARG_QUERY, query); - args.putString(ARG_KEY_SERVER, keyServer); - - frag.setArguments(args); - - return frag; - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.import_keys_server_fragment, container, false); - - mSearchButton = (BootstrapButton) view.findViewById(R.id.import_server_search); - mQueryEditText = (EditText) view.findViewById(R.id.import_server_query); - mServerSpinner = (Spinner) view.findViewById(R.id.import_server_spinner); - - // add keyservers to spinner - mServerAdapter = new ArrayAdapter<String>(getActivity(), - android.R.layout.simple_spinner_item, Preferences.getPreferences(getActivity()) - .getKeyServers()); - mServerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mServerSpinner.setAdapter(mServerAdapter); - if (mServerAdapter.getCount() > 0) { - mServerSpinner.setSelection(0); - } else { - mSearchButton.setEnabled(false); - } - - mSearchButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - String query = mQueryEditText.getText().toString(); - String keyServer = (String) mServerSpinner.getSelectedItem(); - search(query, keyServer); - - // close keyboard after pressing search - InputMethodManager imm = - (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(mQueryEditText.getWindowToken(), 0); - } - }); - - mQueryEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_SEARCH) { - String query = mQueryEditText.getText().toString(); - String keyServer = (String) mServerSpinner.getSelectedItem(); - search(query, keyServer); - - // Don't return true to let the keyboard close itself after pressing search - return false; - } - return false; - } - }); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mImportActivity = (ImportKeysActivity) getActivity(); - - // set displayed values - if (getArguments() != null) { - if (getArguments().containsKey(ARG_QUERY)) { - String query = getArguments().getString(ARG_QUERY); - mQueryEditText.setText(query, TextView.BufferType.EDITABLE); - - Log.d(Constants.TAG, "query: " + query); - } - - if (getArguments().containsKey(ARG_KEY_SERVER)) { - String keyServer = getArguments().getString(ARG_KEY_SERVER); - int keyServerPos = mServerAdapter.getPosition(keyServer); - mServerSpinner.setSelection(keyServerPos); - - Log.d(Constants.TAG, "keyServer: " + keyServer); - } - - if (getArguments().getBoolean(ARG_DISABLE_QUERY_EDIT, false)) { - mQueryEditText.setEnabled(false); - } - } - } - - private void search(String query, String keyServer) { - mImportActivity.loadCallback(null, null, query, keyServer); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java deleted file mode 100644 index 8db643583..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ExportHelper; - -public class KeyListActivity extends DrawerActivity { - - ExportHelper mExportHelper; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mExportHelper = new ExportHelper(this); - - setContentView(R.layout.key_list_activity); - - // now setup navigation drawer in DrawerActivity... - setupDrawerNavigation(savedInstanceState); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.key_list, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_key_list_import: - importKeys(); - return true; - - case R.id.menu_key_list_create: - createKey(); - return true; - - case R.id.menu_key_list_create_expert: - createKeyExpert(); - return true; - - case R.id.menu_key_list_export: - mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true); - return true; - - default: - return super.onOptionsItemSelected(item); - } - } - - private void importKeys() { - Intent intent = new Intent(this, ImportKeysActivity.class); - startActivityForResult(intent, 0); - } - - private void createKey() { - Intent intent = new Intent(this, EditKeyActivity.class); - intent.setAction(EditKeyActivity.ACTION_CREATE_KEY); - intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true); - intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, ""); // show user id view - startActivityForResult(intent, 0); - } - - private void createKeyExpert() { - Intent intent = new Intent(this, EditKeyActivity.class); - intent.setAction(EditKeyActivity.ACTION_CREATE_KEY); - startActivityForResult(intent, 0); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java deleted file mode 100644 index 3e2c96464..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ /dev/null @@ -1,700 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.graphics.Color; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.support.v4.app.Fragment; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.app.ActionBarActivity; -import android.support.v7.widget.SearchView; -import android.text.TextUtils; -import android.view.ActionMode; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.animation.AnimationUtils; -import android.widget.AbsListView.MultiChoiceModeListener; -import android.widget.AdapterView; -import android.widget.Button; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.TextView; -import com.beardedhen.androidbootstrap.BootstrapButton; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ExportHelper; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; -import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter; -import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; -import org.sufficientlysecure.keychain.util.Log; -import se.emilsjolander.stickylistheaders.ApiLevelTooLowException; -import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; -import se.emilsjolander.stickylistheaders.StickyListHeadersListView; - -import java.util.HashMap; - -/** - * Public key list with sticky list headers. It does _not_ extend ListFragment because it uses - * StickyListHeaders library which does not extend upon ListView. - */ -public class KeyListFragment extends Fragment - implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener, - LoaderManager.LoaderCallbacks<Cursor> { - - private KeyListAdapter mAdapter; - private StickyListHeadersListView mStickyList; - - // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 - boolean mListShown; - View mProgressContainer; - View mListContainer; - - private String mCurQuery; - private SearchView mSearchView; - // empty list layout - private BootstrapButton mButtonEmptyCreate; - private BootstrapButton mButtonEmptyImport; - - - /** - * Load custom layout with StickyListView from library - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View root = inflater.inflate(R.layout.key_list_fragment, container, false); - - mStickyList = (StickyListHeadersListView) root.findViewById(R.id.key_list_list); - mStickyList.setOnItemClickListener(this); - - - // empty view - mButtonEmptyCreate = (BootstrapButton) root.findViewById(R.id.key_list_empty_button_create); - mButtonEmptyCreate.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - Intent intent = new Intent(getActivity(), EditKeyActivity.class); - intent.setAction(EditKeyActivity.ACTION_CREATE_KEY); - intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true); - intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, ""); // show user id view - startActivityForResult(intent, 0); - } - }); - mButtonEmptyImport = (BootstrapButton) root.findViewById(R.id.key_list_empty_button_import); - mButtonEmptyImport.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - Intent intent = new Intent(getActivity(), ImportKeysActivity.class); - intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE); - startActivityForResult(intent, 0); - } - }); - - // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 - mListContainer = root.findViewById(R.id.key_list_list_container); - mProgressContainer = root.findViewById(R.id.key_list_progress_container); - mListShown = true; - - return root; - } - - /** - * Define Adapter and Loader on create of Activity - */ - @SuppressLint("NewApi") - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mStickyList.setOnItemClickListener(this); - mStickyList.setAreHeadersSticky(true); - mStickyList.setDrawingListUnderStickyHeader(false); - mStickyList.setFastScrollEnabled(true); - try { - mStickyList.setFastScrollAlwaysVisible(true); - } catch (ApiLevelTooLowException e) { - } - - /* - * ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only - * available for Android >= 3.0 - */ - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); - mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() { - - @Override - public boolean onCreateActionMode(ActionMode mode, Menu menu) { - android.view.MenuInflater inflater = getActivity().getMenuInflater(); - inflater.inflate(R.menu.key_list_multi, menu); - return true; - } - - @Override - public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - return false; - } - - @Override - public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - - // get IDs for checked positions as long array - long[] ids; - - switch (item.getItemId()) { - case R.id.menu_key_list_multi_encrypt: { - ids = mAdapter.getCurrentSelectedMasterKeyIds(); - encrypt(mode, ids); - break; - } - case R.id.menu_key_list_multi_delete: { - ids = mAdapter.getCurrentSelectedMasterKeyIds(); - showDeleteKeyDialog(mode, ids); - break; - } - case R.id.menu_key_list_multi_export: { - ids = mAdapter.getCurrentSelectedMasterKeyIds(); - ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity()); - mExportHelper.showExportKeysDialog( - ids, Constants.Path.APP_DIR_FILE, mAdapter.isAnySecretSelected()); - break; - } - case R.id.menu_key_list_multi_select_all: { - // select all - for (int i = 0; i < mStickyList.getCount(); i++) { - mStickyList.setItemChecked(i, true); - } - break; - } - } - return true; - } - - @Override - public void onDestroyActionMode(ActionMode mode) { - mAdapter.clearSelection(); - } - - @Override - public void onItemCheckedStateChanged(ActionMode mode, int position, long id, - boolean checked) { - if (checked) { - mAdapter.setNewSelection(position, checked); - } else { - mAdapter.removeSelection(position); - } - int count = mStickyList.getCheckedItemCount(); - String keysSelected = getResources().getQuantityString( - R.plurals.key_list_selected_keys, count, count); - mode.setTitle(keysSelected); - } - - }); - } - - // We have a menu item to show in action bar. - setHasOptionsMenu(true); - - // NOTE: Not supported by StickyListHeader, but reimplemented here - // Start out with a progress indicator. - setListShown(false); - - // Create an empty adapter we will use to display the loaded data. - mAdapter = new KeyListAdapter(getActivity(), null, Id.type.public_key); - mStickyList.setAdapter(mAdapter); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - getLoaderManager().initLoader(0, null, this); - } - - // These are the rows that we will retrieve. - static final String[] PROJECTION = new String[]{ - KeyRings._ID, - KeyRings.MASTER_KEY_ID, - KeyRings.USER_ID, - KeyRings.IS_REVOKED, - KeyRings.VERIFIED, - KeyRings.HAS_SECRET - }; - - static final int INDEX_MASTER_KEY_ID = 1; - static final int INDEX_USER_ID = 2; - static final int INDEX_IS_REVOKED = 3; - static final int INDEX_VERIFIED = 4; - static final int INDEX_HAS_SECRET = 5; - - @Override - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - // This is called when a new Loader needs to be created. This - // sample only has one Loader, so we don't care about the ID. - Uri baseUri = KeyRings.buildUnifiedKeyRingsUri(); - String where = null; - String whereArgs[] = null; - if (mCurQuery != null) { - where = KeyRings.USER_ID + " LIKE ?"; - whereArgs = new String[]{"%" + mCurQuery + "%"}; - } - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, null); - } - - @Override - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - mAdapter.setSearchQuery(mCurQuery); - mAdapter.swapCursor(data); - - mStickyList.setAdapter(mAdapter); - - // this view is made visible if no data is available - mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty)); - - // NOTE: Not supported by StickyListHeader, but reimplemented here - // The list should now be shown. - if (isResumed()) { - setListShown(true); - } else { - setListShownNoAnimation(true); - } - } - - @Override - public void onLoaderReset(Loader<Cursor> loader) { - // This is called when the last Cursor provided to onLoadFinished() - // above is about to be closed. We need to make sure we are no - // longer using it. - mAdapter.swapCursor(null); - } - - /** - * On click on item, start key view activity - */ - @Override - public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { - Intent viewIntent = null; - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - viewIntent = new Intent(getActivity(), ViewKeyActivity.class); - } else { - viewIntent = new Intent(getActivity(), ViewKeyActivityJB.class); - } - viewIntent.setData( - KeyRings.buildGenericKeyRingUri(Long.toString(mAdapter.getMasterKeyId(position)))); - startActivity(viewIntent); - } - - @TargetApi(11) - protected void encrypt(ActionMode mode, long[] masterKeyIds) { - Intent intent = new Intent(getActivity(), EncryptActivity.class); - intent.setAction(EncryptActivity.ACTION_ENCRYPT); - intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, masterKeyIds); - // used instead of startActivity set actionbar based on callingPackage - startActivityForResult(intent, 0); - - mode.finish(); - } - - /** - * Show dialog to delete key - * - * @param masterKeyIds - */ - @TargetApi(11) - // TODO: this method needs an overhaul to handle both public and secret keys gracefully! - public void showDeleteKeyDialog(final ActionMode mode, long[] masterKeyIds) { - // Message is received after key is deleted - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { - mode.finish(); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, - masterKeyIds); - - deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog"); - } - - - @Override - public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { - // Get the searchview - MenuItem searchItem = menu.findItem(R.id.menu_key_list_search); - mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem); - - // Execute this when searching - mSearchView.setOnQueryTextListener(this); - - // Erase search result without focus - MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() { - @Override - public boolean onMenuItemActionExpand(MenuItem item) { - return true; - } - - @Override - public boolean onMenuItemActionCollapse(MenuItem item) { - mCurQuery = null; - mSearchView.setQuery("", true); - getLoaderManager().restartLoader(0, null, KeyListFragment.this); - return true; - } - }); - - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public boolean onQueryTextSubmit(String s) { - return true; - } - - @Override - public boolean onQueryTextChange(String s) { - // Called when the action bar search text has changed. Update - // the search filter, and restart the loader to do a new query - // with this filter. - mCurQuery = !TextUtils.isEmpty(s) ? s : null; - getLoaderManager().restartLoader(0, null, this); - return true; - } - - // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 - public void setListShown(boolean shown, boolean animate) { - if (mListShown == shown) { - return; - } - mListShown = shown; - if (shown) { - if (animate) { - mProgressContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_out)); - mListContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_in)); - } - mProgressContainer.setVisibility(View.GONE); - mListContainer.setVisibility(View.VISIBLE); - } else { - if (animate) { - mProgressContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_in)); - mListContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_out)); - } - mProgressContainer.setVisibility(View.VISIBLE); - mListContainer.setVisibility(View.INVISIBLE); - } - } - - // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 - public void setListShown(boolean shown) { - setListShown(shown, true); - } - - // rebuild functionality of ListFragment, http://stackoverflow.com/a/12504097 - public void setListShownNoAnimation(boolean shown) { - setListShown(shown, false); - } - - /** - * Implements StickyListHeadersAdapter from library - */ - private class KeyListAdapter extends HighlightQueryCursorAdapter implements StickyListHeadersAdapter { - private LayoutInflater mInflater; - - private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>(); - - public KeyListAdapter(Context context, Cursor c, int flags) { - super(context, c, flags); - - mInflater = LayoutInflater.from(context); - } - - @Override - public Cursor swapCursor(Cursor newCursor) { - return super.swapCursor(newCursor); - } - - /** - * Bind cursor data to the item list view - * <p/> - * NOTE: CursorAdapter already implements the ViewHolder pattern in its getView() method. - * Thus no ViewHolder is required here. - */ - @Override - public void bindView(View view, Context context, Cursor cursor) { - - { // set name and stuff, common to both key types - TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - - String userId = cursor.getString(INDEX_USER_ID); - String[] userIdSplit = PgpKeyHelper.splitUserId(userId); - if (userIdSplit[0] != null) { - mainUserId.setText(highlightSearchQuery(userIdSplit[0])); - } else { - mainUserId.setText(R.string.user_id_no_name); - } - if (userIdSplit[1] != null) { - mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1])); - mainUserIdRest.setVisibility(View.VISIBLE); - } else { - mainUserIdRest.setVisibility(View.GONE); - } - } - - { // set edit button and revoked info, specific by key type - View statusDivider = (View) view.findViewById(R.id.status_divider); - FrameLayout statusLayout = (FrameLayout) view.findViewById(R.id.status_layout); - Button button = (Button) view.findViewById(R.id.edit); - TextView revoked = (TextView) view.findViewById(R.id.revoked); - ImageView verified = (ImageView) view.findViewById(R.id.verified); - - if (cursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) { - // this is a secret key - show the edit button - statusDivider.setVisibility(View.VISIBLE); - statusLayout.setVisibility(View.VISIBLE); - revoked.setVisibility(View.GONE); - verified.setVisibility(View.GONE); - button.setVisibility(View.VISIBLE); - - final long id = cursor.getLong(INDEX_MASTER_KEY_ID); - button.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 button, show if it's revoked - statusDivider.setVisibility(View.GONE); - button.setVisibility(View.GONE); - - boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0; - if(isRevoked) { - statusLayout.setVisibility(isRevoked ? View.VISIBLE : View.GONE); - revoked.setVisibility(isRevoked ? View.VISIBLE : View.GONE); - verified.setVisibility(View.GONE); - } else { - boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0; - statusLayout.setVisibility(isVerified ? View.VISIBLE : View.GONE); - revoked.setVisibility(View.GONE); - verified.setVisibility(isVerified ? View.VISIBLE : View.GONE); - } - } - } - - } - - public boolean isSecretAvailable(int id) { - if (!mCursor.moveToPosition(id)) { - throw new IllegalStateException("couldn't move cursor to position " + id); - } - - return mCursor.getInt(INDEX_HAS_SECRET) != 0; - } - public long getMasterKeyId(int id) { - if (!mCursor.moveToPosition(id)) { - throw new IllegalStateException("couldn't move cursor to position " + id); - } - - return mCursor.getLong(INDEX_MASTER_KEY_ID); - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.key_list_item, parent, false); - } - - /** - * Creates a new header view and binds the section headers to it. It uses the ViewHolder - * pattern. Most functionality is similar to getView() from Android's CursorAdapter. - * <p/> - * NOTE: The variables mDataValid and mCursor are available due to the super class - * CursorAdapter. - */ - @Override - public View getHeaderView(int position, View convertView, ViewGroup parent) { - HeaderViewHolder holder; - if (convertView == null) { - holder = new HeaderViewHolder(); - convertView = mInflater.inflate(R.layout.key_list_header, parent, false); - holder.mText = (TextView) convertView.findViewById(R.id.stickylist_header_text); - holder.mCount = (TextView) convertView.findViewById(R.id.contacts_num); - convertView.setTag(holder); - } else { - holder = (HeaderViewHolder) convertView.getTag(); - } - - if (!mDataValid) { - // no data available at this point - Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); - return convertView; - } - - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("couldn't move cursor to position " + position); - } - - if (mCursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) { - { // set contact count - int num = mCursor.getCount(); - String contactsTotal = getResources().getQuantityString(R.plurals.n_contacts, num, num); - holder.mCount.setText(contactsTotal); - holder.mCount.setVisibility(View.VISIBLE); - } - - holder.mText.setText(convertView.getResources().getString(R.string.my_keys)); - return convertView; - } - - // set header text as first char in user id - String userId = mCursor.getString(KeyListFragment.INDEX_USER_ID); - String headerText = convertView.getResources().getString(R.string.user_id_no_name); - if (userId != null && userId.length() > 0) { - headerText = "" + userId.subSequence(0, 1).charAt(0); - } - holder.mText.setText(headerText); - holder.mCount.setVisibility(View.GONE); - return convertView; - } - - /** - * Header IDs should be static, position=1 should always return the same Id that is. - */ - @Override - public long getHeaderId(int position) { - if (!mDataValid) { - // no data available at this point - Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); - return -1; - } - - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("couldn't move cursor to position " + position); - } - - // early breakout: all secret keys are assigned id 0 - if (mCursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) { - return 1L; - } - // otherwise, return the first character of the name as ID - String userId = mCursor.getString(KeyListFragment.INDEX_USER_ID); - if (userId != null && userId.length() > 0) { - return userId.charAt(0); - } else { - return Long.MAX_VALUE; - } - } - - class HeaderViewHolder { - TextView mText; - TextView mCount; - } - - /** - * -------------------------- MULTI-SELECTION METHODS -------------- - */ - public void setNewSelection(int position, boolean value) { - mSelection.put(position, value); - notifyDataSetChanged(); - } - - public boolean isAnySecretSelected() { - for (int pos : mSelection.keySet()) { - if(mAdapter.isSecretAvailable(pos)) - return true; - } - return false; - } - - public long[] getCurrentSelectedMasterKeyIds() { - long[] ids = new long[mSelection.size()]; - int i = 0; - // get master key ids - for (int pos : mSelection.keySet()) { - ids[i++] = mAdapter.getMasterKeyId(pos); - } - return ids; - } - - public void removeSelection(int position) { - mSelection.remove(position); - notifyDataSetChanged(); - } - - public void clearSelection() { - mSelection.clear(); - notifyDataSetChanged(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - // let the adapter handle setting up the row views - View v = super.getView(position, convertView, parent); - - /** - * Change color for multi-selection - */ - if (mSelection.get(position) != null) { - // selected position color - v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis)); - } else { - // default color - v.setBackgroundColor(Color.TRANSPARENT); - } - - return v; - } - - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java deleted file mode 100644 index 265bb2139..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.annotation.SuppressLint; -import android.content.Intent; -import android.os.Build; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.Preference; -import android.preference.PreferenceActivity; -import android.preference.PreferenceFragment; -import android.preference.PreferenceScreen; - -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.openpgp.PGPEncryptedData; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference; - -import java.util.List; - -@SuppressLint("NewApi") -public class PreferencesActivity extends PreferenceActivity { - - public static final String ACTION_PREFS_GEN = "org.sufficientlysecure.keychain.ui.PREFS_GEN"; - public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV"; - - private PreferenceScreen mKeyServerPreference = null; - private static Preferences sPreferences; - - @Override - protected void onCreate(Bundle savedInstanceState) { - sPreferences = Preferences.getPreferences(this); - super.onCreate(savedInstanceState); - -// final ActionBar actionBar = getSupportActionBar(); -// actionBar.setDisplayShowTitleEnabled(true); -// actionBar.setDisplayHomeAsUpEnabled(false); -// actionBar.setHomeButtonEnabled(false); - - String action = getIntent().getAction(); - - if (action != null && action.equals(ACTION_PREFS_GEN)) { - addPreferencesFromResource(R.xml.gen_preferences); - - initializePassPassphraceCacheTtl( - (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); - - mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS); - String servers[] = sPreferences.getKeyServers(); - mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers, - servers.length, servers.length)); - mKeyServerPreference - .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference preference) { - Intent intent = new Intent(PreferencesActivity.this, - PreferencesKeyServerActivity.class); - intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS, - sPreferences.getKeyServers()); - startActivityForResult(intent, Id.request.key_server_preference); - return false; - } - }); - - } else if (action != null && action.equals(ACTION_PREFS_ADV)) { - addPreferencesFromResource(R.xml.adv_preferences); - - initializeEncryptionAlgorithm( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM)); - - int[] valueIds = new int[]{Id.choice.compression.none, Id.choice.compression.zip, - Id.choice.compression.zlib, Id.choice.compression.bzip2, }; - String[] entries = new String[]{ - getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", - "ZIP (" + getString(R.string.compression_fast) + ")", - "ZLIB (" + getString(R.string.compression_fast) + ")", - "BZIP2 (" + getString(R.string.compression_very_slow) + ")", }; - String[] values = new String[valueIds.length]; - for (int i = 0; i < values.length; ++i) { - values[i] = "" + valueIds[i]; - } - - initializeHashAlgorithm( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM), - valueIds, entries, values); - - initializeMessageCompression( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION), - valueIds, entries, values); - - initializeFileCompression( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION), - entries, values); - - initializeAsciiArmor( - (CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR)); - - initializeForceV3Signatures( - (CheckBoxPreference) findPreference(Constants.Pref.FORCE_V3_SIGNATURES)); - - } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - // Load the legacy preferences headers - addPreferencesFromResource(R.xml.preference_headers_legacy); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case Id.request.key_server_preference: { - if (resultCode == RESULT_CANCELED || data == null) { - return; - } - String servers[] = data - .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); - sPreferences.setKeyServers(servers); - mKeyServerPreference.setSummary(getResources().getQuantityString( - R.plurals.n_key_servers, servers.length, servers.length)); - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - break; - } - } - } - - /* Called only on Honeycomb and later */ - @Override - public void onBuildHeaders(List<Header> target) { - super.onBuildHeaders(target); - loadHeadersFromResource(R.xml.preference_headers, target); - } - - /** - * This fragment shows the general preferences in android 3.0+ - */ - public static class GeneralPrefsFragment extends PreferenceFragment { - - private PreferenceScreen mKeyServerPreference = null; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.gen_preferences); - - initializePassPassphraceCacheTtl( - (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); - - mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS); - String servers[] = sPreferences.getKeyServers(); - mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers, - servers.length, servers.length)); - mKeyServerPreference - .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference preference) { - Intent intent = new Intent(getActivity(), - PreferencesKeyServerActivity.class); - intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS, - sPreferences.getKeyServers()); - startActivityForResult(intent, Id.request.key_server_preference); - return false; - } - }); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case Id.request.key_server_preference: { - if (resultCode == RESULT_CANCELED || data == null) { - return; - } - String servers[] = data - .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); - sPreferences.setKeyServers(servers); - mKeyServerPreference.setSummary(getResources().getQuantityString( - R.plurals.n_key_servers, servers.length, servers.length)); - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - break; - } - } - } - } - - /** - * This fragment shows the advanced preferences in android 3.0+ - */ - public static class AdvancedPrefsFragment extends PreferenceFragment { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.adv_preferences); - - initializeEncryptionAlgorithm( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM)); - - int[] valueIds = new int[]{Id.choice.compression.none, Id.choice.compression.zip, - Id.choice.compression.zlib, Id.choice.compression.bzip2, }; - String[] entries = new String[]{ - getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", - "ZIP (" + getString(R.string.compression_fast) + ")", - "ZLIB (" + getString(R.string.compression_fast) + ")", - "BZIP2 (" + getString(R.string.compression_very_slow) + ")", }; - String[] values = new String[valueIds.length]; - for (int i = 0; i < values.length; ++i) { - values[i] = "" + valueIds[i]; - } - - initializeHashAlgorithm( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM), - valueIds, entries, values); - - initializeMessageCompression( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION), - valueIds, entries, values); - - initializeFileCompression( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION), - entries, values); - - initializeAsciiArmor( - (CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR)); - - initializeForceV3Signatures( - (CheckBoxPreference) findPreference(Constants.Pref.FORCE_V3_SIGNATURES)); - } - } - - protected boolean isValidFragment(String fragmentName) { - return AdvancedPrefsFragment.class.getName().equals(fragmentName) - || GeneralPrefsFragment.class.getName().equals(fragmentName) - || super.isValidFragment(fragmentName); - } - - private static void initializePassPassphraceCacheTtl(final IntegerListPreference mPassphraseCacheTtl) { - mPassphraseCacheTtl.setValue("" + sPreferences.getPassphraseCacheTtl()); - mPassphraseCacheTtl.setSummary(mPassphraseCacheTtl.getEntry()); - mPassphraseCacheTtl - .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mPassphraseCacheTtl.setValue(newValue.toString()); - mPassphraseCacheTtl.setSummary(mPassphraseCacheTtl.getEntry()); - sPreferences.setPassphraseCacheTtl(Integer.parseInt(newValue.toString())); - return false; - } - }); - } - - private static void initializeEncryptionAlgorithm(final IntegerListPreference mEncryptionAlgorithm) { - int valueIds[] = {PGPEncryptedData.AES_128, PGPEncryptedData.AES_192, - PGPEncryptedData.AES_256, PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH, - PGPEncryptedData.CAST5, PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES, - PGPEncryptedData.IDEA, }; - String entries[] = {"AES-128", "AES-192", "AES-256", "Blowfish", "Twofish", "CAST5", - "DES", "Triple DES", "IDEA", }; - String values[] = new String[valueIds.length]; - for (int i = 0; i < values.length; ++i) { - values[i] = "" + valueIds[i]; - } - mEncryptionAlgorithm.setEntries(entries); - mEncryptionAlgorithm.setEntryValues(values); - mEncryptionAlgorithm.setValue("" + sPreferences.getDefaultEncryptionAlgorithm()); - mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry()); - mEncryptionAlgorithm - .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mEncryptionAlgorithm.setValue(newValue.toString()); - mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry()); - sPreferences.setDefaultEncryptionAlgorithm(Integer.parseInt(newValue - .toString())); - return false; - } - }); - } - - private static void initializeHashAlgorithm - (final IntegerListPreference mHashAlgorithm, int[] valueIds, String[] entries, String[] values) { - valueIds = new int[]{HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160, - HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256, - HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512, }; - entries = new String[]{"MD5", "RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384", - "SHA-512", }; - values = new String[valueIds.length]; - for (int i = 0; i < values.length; ++i) { - values[i] = "" + valueIds[i]; - } - mHashAlgorithm.setEntries(entries); - mHashAlgorithm.setEntryValues(values); - mHashAlgorithm.setValue("" + sPreferences.getDefaultHashAlgorithm()); - mHashAlgorithm.setSummary(mHashAlgorithm.getEntry()); - mHashAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mHashAlgorithm.setValue(newValue.toString()); - mHashAlgorithm.setSummary(mHashAlgorithm.getEntry()); - sPreferences.setDefaultHashAlgorithm(Integer.parseInt(newValue.toString())); - return false; - } - }); - } - - private static void initializeMessageCompression( - final IntegerListPreference mMessageCompression, - int[] valueIds, String[] entries, String[] values) { - mMessageCompression.setEntries(entries); - mMessageCompression.setEntryValues(values); - mMessageCompression.setValue("" + sPreferences.getDefaultMessageCompression()); - mMessageCompression.setSummary(mMessageCompression.getEntry()); - mMessageCompression - .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mMessageCompression.setValue(newValue.toString()); - mMessageCompression.setSummary(mMessageCompression.getEntry()); - sPreferences.setDefaultMessageCompression(Integer.parseInt(newValue - .toString())); - return false; - } - }); - } - - private static void initializeFileCompression - (final IntegerListPreference mFileCompression, String[] entries, String[] values) { - mFileCompression.setEntries(entries); - mFileCompression.setEntryValues(values); - mFileCompression.setValue("" + sPreferences.getDefaultFileCompression()); - mFileCompression.setSummary(mFileCompression.getEntry()); - mFileCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mFileCompression.setValue(newValue.toString()); - mFileCompression.setSummary(mFileCompression.getEntry()); - sPreferences.setDefaultFileCompression(Integer.parseInt(newValue.toString())); - return false; - } - }); - } - - private static void initializeAsciiArmor(final CheckBoxPreference mAsciiArmor) { - mAsciiArmor.setChecked(sPreferences.getDefaultAsciiArmor()); - mAsciiArmor.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mAsciiArmor.setChecked((Boolean) newValue); - sPreferences.setDefaultAsciiArmor((Boolean) newValue); - return false; - } - }); - } - - private static void initializeForceV3Signatures(final CheckBoxPreference mForceV3Signatures) { - mForceV3Signatures.setChecked(sPreferences.getForceV3Signatures()); - mForceV3Signatures - .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mForceV3Signatures.setChecked((Boolean) newValue); - sPreferences.setForceV3Signatures((Boolean) newValue); - return false; - } - }); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java deleted file mode 100644 index 719378274..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.TextView; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; -import org.sufficientlysecure.keychain.ui.widget.Editor; -import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; -import org.sufficientlysecure.keychain.ui.widget.KeyServerEditor; - -import java.util.Vector; - -public class PreferencesKeyServerActivity extends ActionBarActivity implements OnClickListener, - EditorListener { - - public static final String EXTRA_KEY_SERVERS = "key_servers"; - - private LayoutInflater mInflater; - private ViewGroup mEditors; - private View mAdd; - private TextView mTitle; - private TextView mSummary; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // ok - okClicked(); - } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { - @Override - public void onClick(View v) { - // cancel - cancelClicked(); - } - } - ); - - setContentView(R.layout.key_server_preference); - - mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - mTitle = (TextView) findViewById(R.id.title); - mSummary = (TextView) findViewById(R.id.summary); - - mTitle.setText(R.string.label_key_servers); - - mEditors = (ViewGroup) findViewById(R.id.editors); - mAdd = findViewById(R.id.add); - mAdd.setOnClickListener(this); - - Intent intent = getIntent(); - String servers[] = intent.getStringArrayExtra(EXTRA_KEY_SERVERS); - if (servers != null) { - for (String serv : servers) { - KeyServerEditor view = (KeyServerEditor) mInflater.inflate( - R.layout.key_server_editor, mEditors, false); - view.setEditorListener(this); - view.setValue(serv); - mEditors.addView(view); - } - } - } - - public void onDeleted(Editor editor, boolean wasNewItem) { - // nothing to do - } - - @Override - public void onEdited() { - - } - - public void onClick(View v) { - KeyServerEditor view = (KeyServerEditor) mInflater.inflate(R.layout.key_server_editor, - mEditors, false); - view.setEditorListener(this); - mEditors.addView(view); - } - - private void cancelClicked() { - setResult(RESULT_CANCELED, null); - finish(); - } - - private void okClicked() { - Intent data = new Intent(); - Vector<String> servers = new Vector<String>(); - for (int i = 0; i < mEditors.getChildCount(); ++i) { - KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i); - String tmp = editor.getValue(); - if (tmp.length() > 0) { - servers.add(tmp); - } - } - String[] dummy = new String[0]; - data.putExtra(EXTRA_KEY_SERVERS, servers.toArray(dummy)); - setResult(RESULT_OK, data); - finish(); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java deleted file mode 100644 index 874703704..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; -import android.view.View; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ActionBarHelper; - -public class SelectPublicKeyActivity extends ActionBarActivity { - - // Actions for internal use only: - public static final String ACTION_SELECT_PUBLIC_KEYS = Constants.INTENT_PREFIX - + "SELECT_PUBLIC_KEYRINGS"; - - public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids"; - - public static final String RESULT_EXTRA_MASTER_KEY_IDS = "master_key_ids"; - public static final String RESULT_EXTRA_USER_IDS = "user_ids"; - - SelectPublicKeyFragment mSelectFragment; - - long mSelectedMasterKeyIds[]; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // ok - okClicked(); - } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { - @Override - public void onClick(View v) { - // cancel - cancelClicked(); - } - } - ); - - setContentView(R.layout.select_public_key_activity); - - setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); - - handleIntent(getIntent()); - - // Check that the activity is using the layout version with - // the fragment_container FrameLayout - if (findViewById(R.id.select_public_key_fragment_container) != null) { - - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; - } - - // Create an instance of the fragment - mSelectFragment = SelectPublicKeyFragment.newInstance(mSelectedMasterKeyIds); - - // Add the fragment to the 'fragment_container' FrameLayout - getSupportFragmentManager().beginTransaction() - .add(R.id.select_public_key_fragment_container, mSelectFragment).commit(); - } - - // TODO: reimplement! - // mFilterLayout = findViewById(R.id.layout_filter); - // mFilterInfo = (TextView) mFilterLayout.findViewById(R.id.filterInfo); - // mClearFilterButton = (Button) mFilterLayout.findViewById(R.id.btn_clear); - // - // mClearFilterButton.setOnClickListener(new OnClickListener() { - // public void onClick(View v) { - // handleIntent(new Intent()); - // } - // }); - - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - handleIntent(intent); - } - - private void handleIntent(Intent intent) { - // TODO: reimplement search! - - // String searchString = null; - // if (Intent.ACTION_SEARCH.equals(intent.getAction())) { - // searchString = intent.getStringExtra(SearchManager.QUERY); - // if (searchString != null && searchString.trim().length() == 0) { - // searchString = null; - // } - // } - - // if (searchString == null) { - // mFilterLayout.setVisibility(View.GONE); - // } else { - // mFilterLayout.setVisibility(View.VISIBLE); - // mFilterInfo.setText(getString(R.string.filterInfo, searchString)); - // } - - // preselected master keys - mSelectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); - } - - private void cancelClicked() { - setResult(RESULT_CANCELED, null); - finish(); - } - - private void okClicked() { - Intent data = new Intent(); - data.putExtra(RESULT_EXTRA_MASTER_KEY_IDS, mSelectFragment.getSelectedMasterKeyIds()); - data.putExtra(RESULT_EXTRA_USER_IDS, mSelectFragment.getSelectedUserIds()); - setResult(RESULT_OK, data); - finish(); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java deleted file mode 100644 index 9bfe3eaa9..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Context; -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.EditText; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.ListView; -import android.widget.ProgressBar; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; -import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter; - -import java.util.Date; -import java.util.Vector; - -public class SelectPublicKeyFragment extends ListFragmentWorkaround implements TextWatcher, - LoaderManager.LoaderCallbacks<Cursor> { - public static final String ARG_PRESELECTED_KEY_IDS = "preselected_key_ids"; - - private SelectKeyCursorAdapter mAdapter; - private EditText mSearchView; - private long mSelectedMasterKeyIds[]; - private String mCurQuery; - - // copied from ListFragment - static final int INTERNAL_EMPTY_ID = 0x00ff0001; - static final int INTERNAL_PROGRESS_CONTAINER_ID = 0x00ff0002; - static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003; - // added for search view - static final int SEARCH_ID = 0x00ff0004; - - /** - * Creates new instance of this fragment - */ - public static SelectPublicKeyFragment newInstance(long[] preselectedKeyIds) { - SelectPublicKeyFragment frag = new SelectPublicKeyFragment(); - Bundle args = new Bundle(); - - args.putLongArray(ARG_PRESELECTED_KEY_IDS, preselectedKeyIds); - - frag.setArguments(args); - - return frag; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mSelectedMasterKeyIds = getArguments().getLongArray(ARG_PRESELECTED_KEY_IDS); - } - - /** - * Copied from ListFragment and added EditText for search on top of list. - * We do not use a custom layout here, because this breaks the progress bar functionality - * of ListFragment. - * - * @param inflater - * @param container - * @param savedInstanceState - * @return - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - final Context context = getActivity(); - - FrameLayout root = new FrameLayout(context); - - // ------------------------------------------------------------------ - - LinearLayout pframe = new LinearLayout(context); - pframe.setId(INTERNAL_PROGRESS_CONTAINER_ID); - pframe.setOrientation(LinearLayout.VERTICAL); - pframe.setVisibility(View.GONE); - pframe.setGravity(Gravity.CENTER); - - ProgressBar progress = new ProgressBar(context, null, - android.R.attr.progressBarStyleLarge); - pframe.addView(progress, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - - root.addView(pframe, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - - // ------------------------------------------------------------------ - - FrameLayout lframe = new FrameLayout(context); - lframe.setId(INTERNAL_LIST_CONTAINER_ID); - - TextView tv = new TextView(getActivity()); - tv.setId(INTERNAL_EMPTY_ID); - tv.setGravity(Gravity.CENTER); - lframe.addView(tv, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - - // Added for search view: linearLayout, mSearchView - LinearLayout linearLayout = new LinearLayout(context); - linearLayout.setOrientation(LinearLayout.VERTICAL); - - mSearchView = new EditText(context); - mSearchView.setId(SEARCH_ID); - mSearchView.setHint(R.string.menu_search); - mSearchView.setCompoundDrawablesWithIntrinsicBounds( - getResources().getDrawable(R.drawable.ic_action_search), null, null, null); - - linearLayout.addView(mSearchView, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - - ListView lv = new ListView(getActivity()); - lv.setId(android.R.id.list); - lv.setDrawSelectorOnTop(false); - linearLayout.addView(lv, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - - lframe.addView(linearLayout, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - - root.addView(lframe, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - - // ------------------------------------------------------------------ - - root.setLayoutParams(new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - - return root; - } - - /** - * Define Adapter and Loader on create of Activity - */ - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - - // Give some text to display if there is no data. In a real - // application this would come from a resource. - setEmptyText(getString(R.string.list_empty)); - - mSearchView.addTextChangedListener(this); - - mAdapter = new SelectKeyCursorAdapter(getActivity(), null, 0, getListView(), Id.type.public_key); - - setListAdapter(mAdapter); - - // Start out with a progress indicator. - setListShown(false); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - getLoaderManager().initLoader(0, null, this); - } - - /** - * Selects items based on master key ids in list view - * - * @param masterKeyIds - */ - private void preselectMasterKeyIds(long[] masterKeyIds) { - if (masterKeyIds != null) { - for (int i = 0; i < getListView().getCount(); ++i) { - long keyId = mAdapter.getMasterKeyId(i); - for (long masterKeyId : masterKeyIds) { - if (keyId == masterKeyId) { - getListView().setItemChecked(i, true); - break; - } - } - } - } - } - - /** - * Returns all selected master key ids - * - * @return - */ - public long[] getSelectedMasterKeyIds() { - // mListView.getCheckedItemIds() would give the row ids of the KeyRings not the master key - // ids! - Vector<Long> vector = new Vector<Long>(); - for (int i = 0; i < getListView().getCount(); ++i) { - if (getListView().isItemChecked(i)) { - vector.add(mAdapter.getMasterKeyId(i)); - } - } - - // convert to long array - long[] selectedMasterKeyIds = new long[vector.size()]; - for (int i = 0; i < vector.size(); ++i) { - selectedMasterKeyIds[i] = vector.get(i); - } - - return selectedMasterKeyIds; - } - - /** - * Returns all selected user ids - * - * @return - */ - public String[] getSelectedUserIds() { - Vector<String> userIds = new Vector<String>(); - for (int i = 0; i < getListView().getCount(); ++i) { - if (getListView().isItemChecked(i)) { - userIds.add((String) mAdapter.getUserId(i)); - } - } - - // make empty array to not return null - String userIdArray[] = new String[0]; - return userIds.toArray(userIdArray); - } - - @Override - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - Uri baseUri = KeyRings.buildUnifiedKeyRingsUri(); - - // These are the rows that we will retrieve. - long now = new Date().getTime() / 1000; - String[] projection = new String[]{ - KeyRings._ID, - KeyRings.MASTER_KEY_ID, - UserIds.USER_ID, - "(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" - +" WHERE k." + Keys.MASTER_KEY_ID + " = " - + KeychainDatabase.Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " AND k." + Keys.IS_REVOKED + " = '0'" - + " AND k." + Keys.CAN_ENCRYPT + " = '1'" - + ") AS " + SelectKeyCursorAdapter.PROJECTION_ROW_AVAILABLE, - "(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" - + " WHERE k." + Keys.MASTER_KEY_ID + " = " - + KeychainDatabase.Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " AND k." + Keys.IS_REVOKED + " = '0'" - + " AND k." + Keys.CAN_ENCRYPT + " = '1'" - + " AND k." + Keys.CREATION + " <= '" + now + "'" - + " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY + " >= '" + now + "' )" - + ") AS " + SelectKeyCursorAdapter.PROJECTION_ROW_VALID, }; - - String inMasterKeyList = null; - if (mSelectedMasterKeyIds != null && mSelectedMasterKeyIds.length > 0) { - inMasterKeyList = Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + " IN ("; - for (int i = 0; i < mSelectedMasterKeyIds.length; ++i) { - if (i != 0) { - inMasterKeyList += ", "; - } - inMasterKeyList += DatabaseUtils.sqlEscapeString("" + mSelectedMasterKeyIds[i]); - } - inMasterKeyList += ")"; - } - - String orderBy = UserIds.USER_ID + " ASC"; - if (inMasterKeyList != null) { - // sort by selected master keys - orderBy = inMasterKeyList + " DESC, " + orderBy; - } - String where = null; - String whereArgs[] = null; - if (mCurQuery != null) { - where = UserIds.USER_ID + " LIKE ?"; - whereArgs = new String[]{"%" + mCurQuery + "%"}; - } - - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, projection, where, whereArgs, orderBy); - } - - @Override - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - mAdapter.setSearchQuery(mCurQuery); - mAdapter.swapCursor(data); - - // The list should now be shown. - if (isResumed()) { - setListShown(true); - } else { - setListShownNoAnimation(true); - } - - // preselect given master keys - preselectMasterKeyIds(mSelectedMasterKeyIds); - } - - @Override - public void onLoaderReset(Loader<Cursor> loader) { - // This is called when the last Cursor provided to onLoadFinished() - // above is about to be closed. We need to make sure we are no - // longer using it. - mAdapter.swapCursor(null); - } - - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { - - } - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { - - } - - @Override - public void afterTextChanged(Editable editable) { - mCurQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null; - getLoaderManager().restartLoader(0, null, this); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java deleted file mode 100644 index 0ff88d97c..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyActivity.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; - -import org.sufficientlysecure.keychain.R; - -public class SelectSecretKeyActivity extends ActionBarActivity { - - public static final String EXTRA_FILTER_CERTIFY = "filter_certify"; - - public static final String RESULT_EXTRA_MASTER_KEY_ID = "master_key_id"; - - private boolean mFilterCertify; - private SelectSecretKeyFragment mSelectFragment; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.select_secret_key_activity); - - final ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(false); - actionBar.setHomeButtonEnabled(false); - - mFilterCertify = getIntent().getBooleanExtra(EXTRA_FILTER_CERTIFY, false); - - // Check that the activity is using the layout version with - // the fragment_container FrameLayout - if (findViewById(R.id.select_secret_key_fragment_container) != null) { - - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; - } - - // Create an instance of the fragment - mSelectFragment = SelectSecretKeyFragment.newInstance(mFilterCertify); - - // Add the fragment to the 'fragment_container' FrameLayout - getSupportFragmentManager().beginTransaction() - .add(R.id.select_secret_key_fragment_container, mSelectFragment).commit(); - } - } - - /** - * This is executed by SelectSecretKeyFragment after clicking on an item - * - * @param selectedUri - */ - public void afterListSelection(Uri selectedUri) { - Intent data = new Intent(); - data.setData(selectedUri); - - setResult(RESULT_OK, data); - finish(); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java deleted file mode 100644 index 9987facbc..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.ListFragment; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ListView; - -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; -import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter; - -import java.util.Date; - -public class SelectSecretKeyFragment extends ListFragment implements - LoaderManager.LoaderCallbacks<Cursor> { - - private SelectSecretKeyActivity mActivity; - private SelectKeyCursorAdapter mAdapter; - private ListView mListView; - - private boolean mFilterCertify; - - private static final String ARG_FILTER_CERTIFY = "filter_certify"; - - /** - * Creates new instance of this fragment - */ - public static SelectSecretKeyFragment newInstance(boolean filterCertify) { - SelectSecretKeyFragment frag = new SelectSecretKeyFragment(); - - Bundle args = new Bundle(); - args.putBoolean(ARG_FILTER_CERTIFY, filterCertify); - frag.setArguments(args); - - return frag; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mFilterCertify = getArguments().getBoolean(ARG_FILTER_CERTIFY); - } - - /** - * Define Adapter and Loader on create of Activity - */ - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mActivity = (SelectSecretKeyActivity) getActivity(); - mListView = getListView(); - - mListView.setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { - long masterKeyId = mAdapter.getMasterKeyId(position); - Uri result = KeyRings.buildGenericKeyRingUri(String.valueOf(masterKeyId)); - - // return data to activity, which results in finishing it - mActivity.afterListSelection(result); - } - }); - - // Give some text to display if there is no data. In a real - // application this would come from a resource. - setEmptyText(getString(R.string.list_empty)); - - mAdapter = new SelectKeyCursorAdapter(mActivity, null, 0, mListView, Id.type.secret_key); - - setListAdapter(mAdapter); - - // Start out with a progress indicator. - setListShown(false); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - getLoaderManager().initLoader(0, null, this); - } - - @Override - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - // This is called when a new Loader needs to be created. This - // sample only has one Loader, so we don't care about the ID. - Uri baseUri = KeyRings.buildUnifiedKeyRingsUri(); - - // These are the rows that we will retrieve. - long now = new Date().getTime() / 1000; - String[] projection = new String[]{ - KeyRings._ID, - KeyRings.MASTER_KEY_ID, - UserIds.USER_ID, - "(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" - + " WHERE k." + Keys.MASTER_KEY_ID + " = " - + KeychainDatabase.Tables.KEYS + "." + KeyRings.MASTER_KEY_ID - + " AND k." + Keys.CAN_CERTIFY + " = '1'" - + ") AS cert", - "(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" - +" WHERE k." + Keys.MASTER_KEY_ID + " = " - + KeychainDatabase.Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " AND k." + Keys.IS_REVOKED + " = '0'" - + " AND k." + Keys.CAN_SIGN + " = '1'" - + ") AS " + SelectKeyCursorAdapter.PROJECTION_ROW_AVAILABLE, - "(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" - + " WHERE k." + Keys.MASTER_KEY_ID + " = " - + KeychainDatabase.Tables.KEYS + "." + Keys.MASTER_KEY_ID - + " AND k." + Keys.IS_REVOKED + " = '0'" - + " AND k." + Keys.CAN_SIGN + " = '1'" - + " AND k." + Keys.CREATION + " <= '" + now + "'" - + " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY + " >= '" + now + "' )" - + ") AS " + SelectKeyCursorAdapter.PROJECTION_ROW_VALID, }; - - String orderBy = UserIds.USER_ID + " ASC"; - - String where = Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NOT NULL"; - if (mFilterCertify) { - where += " AND (cert > 0)"; - } - - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, projection, where, null, orderBy); - } - - @Override - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - mAdapter.swapCursor(data); - - // The list should now be shown. - if (isResumed()) { - setListShown(true); - } else { - setListShownNoAnimation(true); - } - } - - @Override - public void onLoaderReset(Loader<Cursor> loader) { - // This is called when the last Cursor provided to onLoadFinished() - // above is about to be closed. We need to make sure we are no - // longer using it. - mAdapter.swapCursor(null); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java deleted file mode 100644 index 514951385..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyLayoutFragment.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract; - -public class SelectSecretKeyLayoutFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { - - private TextView mKeyUserId; - private TextView mKeyUserIdRest; - private TextView mKeyMasterKeyIdHex; - private TextView mNoKeySelected; - private BootstrapButton mSelectKeyButton; - private Boolean mFilterCertify; - - private Uri mReceivedUri = null; - - private SelectSecretKeyCallback mCallback; - - private static final int REQUEST_CODE_SELECT_KEY = 8882; - - private static final int LOADER_ID = 0; - - //The Projection we will retrieve, Master Key ID is for convenience sake, - //to avoid having to pass the Key Around - final String[] PROJECTION = new String[] { - KeychainContract.Keys.MASTER_KEY_ID, - KeychainContract.UserIds.USER_ID - }; - final int INDEX_MASTER_KEY_ID = 0; - final int INDEX_USER_ID = 1; - - public interface SelectSecretKeyCallback { - void onKeySelected(long secretKeyId); - } - - public void setCallback(SelectSecretKeyCallback callback) { - mCallback = callback; - } - - public void setFilterCertify(Boolean filterCertify) { - mFilterCertify = filterCertify; - } - - public void setNoKeySelected() { - mNoKeySelected.setVisibility(View.VISIBLE); - mKeyUserId.setVisibility(View.GONE); - mKeyUserIdRest.setVisibility(View.GONE); - mKeyMasterKeyIdHex.setVisibility(View.GONE); - } - - public void setSelectedKeyData(String userName, String email, String masterKeyHex) { - - mNoKeySelected.setVisibility(View.GONE); - - mKeyUserId.setText(userName); - mKeyUserIdRest.setText(email); - mKeyMasterKeyIdHex.setText(masterKeyHex); - - mKeyUserId.setVisibility(View.VISIBLE); - mKeyUserIdRest.setVisibility(View.VISIBLE); - mKeyMasterKeyIdHex.setVisibility(View.VISIBLE); - - } - - public void setError(String error) { - mNoKeySelected.requestFocus(); - mNoKeySelected.setError(error); - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.select_secret_key_layout_fragment, container, false); - - mNoKeySelected = (TextView) view.findViewById(R.id.no_key_selected); - mKeyUserId = (TextView) view.findViewById(R.id.select_secret_key_user_id); - mKeyUserIdRest = (TextView) view.findViewById(R.id.select_secret_key_user_id_rest); - mKeyMasterKeyIdHex = (TextView) view.findViewById(R.id.select_secret_key_master_key_hex); - mSelectKeyButton = (BootstrapButton) view - .findViewById(R.id.select_secret_key_select_key_button); - mFilterCertify = false; - mSelectKeyButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - startSelectKeyActivity(); - } - }); - - return view; - } - - //For AppSettingsFragment - public void selectKey(long masterKeyId) { - Uri buildUri = KeychainContract.KeyRings.buildGenericKeyRingUri(String.valueOf(masterKeyId)); - mReceivedUri = buildUri; - getActivity().getSupportLoaderManager().restartLoader(LOADER_ID, null, this); - } - - private void startSelectKeyActivity() { - Intent intent = new Intent(getActivity(), SelectSecretKeyActivity.class); - intent.putExtra(SelectSecretKeyActivity.EXTRA_FILTER_CERTIFY, mFilterCertify); - startActivityForResult(intent, REQUEST_CODE_SELECT_KEY); - } - - @Override - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - Uri uri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(mReceivedUri); - //We don't care about the Loader id - return new CursorLoader(getActivity(), uri, PROJECTION, null, null, null); - } - - @Override - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - if (data.moveToFirst()) { - String userName, email, masterKeyHex; - String userID = data.getString(INDEX_USER_ID); - long masterKeyID = data.getLong(INDEX_MASTER_KEY_ID); - - String splitUserID[] = PgpKeyHelper.splitUserId(userID); - - if (splitUserID[0] != null) { - userName = splitUserID[0]; - } else { - userName = getActivity().getResources().getString(R.string.user_id_no_name); - } - - if (splitUserID[1] != null) { - email = splitUserID[1]; - } else { - email = getActivity().getResources().getString(R.string.error_user_id_no_email); - } - - //TODO Can the cursor return invalid values for the Master Key ? - masterKeyHex = PgpKeyHelper.convertKeyIdToHexShort(masterKeyID); - - //Set the data - setSelectedKeyData(userName, email, masterKeyHex); - - //Give value to the callback - mCallback.onKeySelected(masterKeyID); - } else { - //Set The empty View - setNoKeySelected(); - } - - } - - @Override - public void onLoaderReset(Loader<Cursor> loader) { - return; - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CODE_SELECT_KEY: { - if (resultCode == Activity.RESULT_OK) { - mReceivedUri = data.getData(); - - //Must be restartLoader() or the data will not be updated on selecting a new key - getActivity().getSupportLoaderManager().restartLoader(0, null, this); - - mKeyUserId.setError(null); - } - break; - } - - default: - super.onActivityResult(requestCode, resultCode, data); - - break; - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java deleted file mode 100644 index 0e231e6a8..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2011 Senecaso - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.ProgressDialog; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.support.v7.app.ActionBarActivity; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ArrayAdapter; -import android.widget.Spinner; -import android.widget.Toast; -import com.beardedhen.androidbootstrap.BootstrapButton; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.Preferences; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.util.Log; - -/** - * Sends the selected public key to a keyserver - */ -public class UploadKeyActivity extends ActionBarActivity { - private BootstrapButton mUploadButton; - private Spinner mKeyServerSpinner; - - private Uri mDataUri; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.key_server_export); - - mUploadButton = (BootstrapButton) findViewById(R.id.btn_export_to_server); - mKeyServerSpinner = (Spinner) findViewById(R.id.sign_key_keyserver); - - ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, - android.R.layout.simple_spinner_item, Preferences.getPreferences(this) - .getKeyServers()); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mKeyServerSpinner.setAdapter(adapter); - if (adapter.getCount() > 0) { - mKeyServerSpinner.setSelection(0); - } else { - mUploadButton.setEnabled(false); - } - - mUploadButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - uploadKey(); - } - }); - - mDataUri = getIntent().getData(); - if (mDataUri == null) { - Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!"); - finish(); - return; - } - } - - private void uploadKey() { - // Send all information needed to service to upload key in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_UPLOAD_KEYRING); - - // set data uri as path to keyring - intent.setData(mDataUri); - - // fill values for this action - Bundle data = new Bundle(); - - String server = (String) mKeyServerSpinner.getSelectedItem(); - data.putString(KeychainIntentService.UPLOAD_KEY_SERVER, server); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Message is received after uploading is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this, - getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - - Toast.makeText(UploadKeyActivity.this, R.string.key_send_success, - Toast.LENGTH_SHORT).show(); - finish(); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - saveHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java deleted file mode 100644 index 294fadab2..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.text.format.DateFormat; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.TextView; - -import org.spongycastle.bcpg.SignatureSubpacket; -import org.spongycastle.bcpg.SignatureSubpacketTags; -import org.spongycastle.bcpg.sig.RevocationReason; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.Log; - -import java.security.SignatureException; -import java.util.Date; - -public class ViewCertActivity extends ActionBarActivity - implements LoaderManager.LoaderCallbacks<Cursor> { - - // These are the rows that we will retrieve. - static final String[] PROJECTION = new String[]{ - Certs.MASTER_KEY_ID, - Certs.USER_ID, - Certs.TYPE, - Certs.CREATION, - Certs.KEY_ID_CERTIFIER, - Certs.SIGNER_UID, - Certs.DATA, - }; - private static final int INDEX_MASTER_KEY_ID = 0; - private static final int INDEX_USER_ID = 1; - private static final int INDEX_TYPE = 2; - private static final int INDEX_CREATION = 3; - private static final int INDEX_KEY_ID_CERTIFIER = 4; - private static final int INDEX_SIGNER_UID = 5; - private static final int INDEX_DATA = 6; - - private Uri mDataUri; - - private long mSignerKeyId; - - private TextView mSigneeKey, mSigneeUid, mAlgorithm, mType, mRReason, mCreation; - private TextView mSignerKey, mSignerUid, mStatus; - private View mRowReason; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - - setContentView(R.layout.view_cert_activity); - - mStatus = (TextView) findViewById(R.id.status); - mSigneeKey = (TextView) findViewById(R.id.signee_key); - mSigneeUid = (TextView) findViewById(R.id.signee_uid); - mAlgorithm = (TextView) findViewById(R.id.algorithm); - mType = (TextView) findViewById(R.id.signature_type); - mRReason = (TextView) findViewById(R.id.reason); - mCreation = (TextView) findViewById(R.id.creation); - - mSignerKey = (TextView) findViewById(R.id.signer_key_id); - mSignerUid = (TextView) findViewById(R.id.signer_uid); - - mRowReason = findViewById(R.id.row_reason); - - mDataUri = getIntent().getData(); - if (mDataUri == null) { - Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!"); - finish(); - return; - } - - getSupportLoaderManager().initLoader(0, null, this); - } - - @Override - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(this, mDataUri, PROJECTION, null, null, null); - } - - @Override - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - if (data.moveToFirst()) { - String signeeKey = "0x" + PgpKeyHelper.convertKeyIdToHex(data.getLong(INDEX_MASTER_KEY_ID)); - mSigneeKey.setText(signeeKey); - - String signeeUid = data.getString(INDEX_USER_ID); - mSigneeUid.setText(signeeUid); - - Date creationDate = new Date(data.getLong(INDEX_CREATION) * 1000); - mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format(creationDate)); - - mSignerKeyId = data.getLong(INDEX_KEY_ID_CERTIFIER); - String signerKey = "0x" + PgpKeyHelper.convertKeyIdToHex(mSignerKeyId); - mSignerKey.setText(signerKey); - - String signerUid = data.getString(INDEX_SIGNER_UID); - if (signerUid != null) { - mSignerUid.setText(signerUid); - } else { - mSignerUid.setText(R.string.unknown_uid); - } - - PGPSignature sig = PgpConversionHelper.BytesToPGPSignature(data.getBlob(INDEX_DATA)); - PGPKeyRing signeeRing = ProviderHelper.getPGPKeyRing(this, - KeychainContract.KeyRingData.buildPublicKeyRingUri( - Long.toString(data.getLong(INDEX_MASTER_KEY_ID)))); - PGPKeyRing signerRing = ProviderHelper.getPGPKeyRing(this, - KeychainContract.KeyRingData.buildPublicKeyRingUri( - Long.toString(sig.getKeyID()))); - - if (signerRing != null) { - try { - sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME), signeeRing.getPublicKey()); - if (sig.verifyCertification(signeeUid, signerRing.getPublicKey())) { - mStatus.setText("ok"); - mStatus.setTextColor(getResources().getColor(R.color.bbutton_success)); - } else { - mStatus.setText("failed!"); - mStatus.setTextColor(getResources().getColor(R.color.alert)); - } - } catch (SignatureException e) { - mStatus.setText("error!"); - mStatus.setTextColor(getResources().getColor(R.color.alert)); - } catch (PGPException e) { - mStatus.setText("error!"); - mStatus.setTextColor(getResources().getColor(R.color.alert)); - } - } else { - mStatus.setText("key unavailable"); - mStatus.setTextColor(getResources().getColor(R.color.black)); - } - - String algorithmStr = PgpKeyHelper.getAlgorithmInfo(sig.getKeyAlgorithm(), 0); - mAlgorithm.setText(algorithmStr); - - mRowReason.setVisibility(View.GONE); - switch (data.getInt(INDEX_TYPE)) { - case PGPSignature.DEFAULT_CERTIFICATION: - mType.setText(R.string.cert_default); - break; - case PGPSignature.NO_CERTIFICATION: - mType.setText(R.string.cert_none); - break; - case PGPSignature.CASUAL_CERTIFICATION: - mType.setText(R.string.cert_casual); - break; - case PGPSignature.POSITIVE_CERTIFICATION: - mType.setText(R.string.cert_positive); - break; - case PGPSignature.CERTIFICATION_REVOCATION: { - mType.setText(R.string.cert_revoke); - if (sig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.REVOCATION_REASON)) { - SignatureSubpacket p = sig.getHashedSubPackets().getSubpacket( - SignatureSubpacketTags.REVOCATION_REASON); - // For some reason, this is missing in SignatureSubpacketInputStream:146 - if (!(p instanceof RevocationReason)) { - p = new RevocationReason(false, p.getData()); - } - String reason = ((RevocationReason) p).getRevocationDescription(); - mRReason.setText(reason); - mRowReason.setVisibility(View.VISIBLE); - } - break; - } - } - } - } - - @Override - public void onLoaderReset(Loader<Cursor> loader) { - } - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.view_cert, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_view_cert_view_signer: - // can't do this before the data is initialized - Intent viewIntent = null; - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - viewIntent = new Intent(this, ViewKeyActivity.class); - } else { - viewIntent = new Intent(this, ViewKeyActivityJB.class); - } - // - long signerMasterKeyId = ProviderHelper.getMasterKeyId(this, - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(mSignerKeyId)) - ); - // TODO notify user of this, maybe offer download? - if (mSignerKeyId == 0L) - return true; - viewIntent.setData(KeyRings.buildGenericKeyRingUri( - Long.toString(signerMasterKeyId)) - ); - startActivity(viewIntent); - return true; - } - return super.onOptionsItemSelected(item); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java deleted file mode 100644 index cce34139c..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2013 Bahtiar 'kalkin' Gadimov - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.support.v4.view.ViewPager; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.view.Menu; -import android.view.MenuItem; -import android.view.Window; -import android.widget.Toast; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.helper.ExportHelper; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter; -import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment; - -import java.util.ArrayList; -import java.util.HashMap; - -public class ViewKeyActivity extends ActionBarActivity { - - ExportHelper mExportHelper; - - protected Uri mDataUri; - - public static final String EXTRA_SELECTED_TAB = "selectedTab"; - - ViewPager mViewPager; - TabsAdapter mTabsAdapter; - - private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006; - - @Override - protected void onCreate(Bundle savedInstanceState) { - requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - super.onCreate(savedInstanceState); - - mExportHelper = new ExportHelper(this); - - // let the actionbar look like Android's contact app - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setIcon(android.R.color.transparent); - actionBar.setHomeButtonEnabled(true); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - - setContentView(R.layout.view_key_activity); - - mViewPager = (ViewPager) findViewById(R.id.pager); - - mTabsAdapter = new TabsAdapter(this, mViewPager); - - int selectedTab = 0; - Intent intent = getIntent(); - if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) { - selectedTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB); - } - - mDataUri = getIntent().getData(); - - Bundle mainBundle = new Bundle(); - mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, mDataUri); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_main)), - ViewKeyMainFragment.class, mainBundle, (selectedTab == 0)); - - Bundle certBundle = new Bundle(); - certBundle.putParcelable(ViewKeyCertsFragment.ARG_DATA_URI, mDataUri); - mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.key_view_tab_certs)), - ViewKeyCertsFragment.class, certBundle, (selectedTab == 1)); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.key_view, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - Intent homeIntent = new Intent(this, KeyListActivity.class); - homeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(homeIntent); - return true; - case R.id.menu_key_view_update: - updateFromKeyserver(mDataUri); - return true; - case R.id.menu_key_view_export_keyserver: - uploadToKeyserver(mDataUri); - return true; - case R.id.menu_key_view_export_file: - exportToFile(mDataUri); - return true; - case R.id.menu_key_view_share_default_fingerprint: - shareKey(mDataUri, true); - return true; - case R.id.menu_key_view_share_default: - shareKey(mDataUri, false); - return true; - case R.id.menu_key_view_share_qr_code_fingerprint: - shareKeyQrCode(mDataUri, true); - return true; - case R.id.menu_key_view_share_qr_code: - shareKeyQrCode(mDataUri, false); - return true; - case R.id.menu_key_view_share_nfc: - shareNfc(); - return true; - case R.id.menu_key_view_share_clipboard: - copyToClipboard(mDataUri); - return true; - case R.id.menu_key_view_delete: { - deleteKey(mDataUri); - return true; - } - } - return super.onOptionsItemSelected(item); - } - - private void exportToFile(Uri dataUri) { - Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri); - - HashMap<String, Object> data = ProviderHelper.getGenericData(this, - baseUri, - new String[]{KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET}, - new int[]{ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER}); - - mExportHelper.showExportKeysDialog( - new long[]{(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)}, - Constants.Path.APP_DIR_FILE, - ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) == 1) - ); - } - - private void uploadToKeyserver(Uri dataUri) { - Intent uploadIntent = new Intent(this, UploadKeyActivity.class); - uploadIntent.setData(dataUri); - startActivityForResult(uploadIntent, Id.request.export_to_server); - } - - private void updateFromKeyserver(Uri dataUri) { - byte[] blob = (byte[]) ProviderHelper.getGenericData( - this, KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri), - KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); - String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob); - - Intent queryIntent = new Intent(this, ImportKeysActivity.class); - queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN); - queryIntent.putExtra(ImportKeysActivity.EXTRA_FINGERPRINT, fingerprint); - - startActivityForResult(queryIntent, RESULT_CODE_LOOKUP_KEY); - } - - private void shareKey(Uri dataUri, boolean fingerprintOnly) { - String content; - if (fingerprintOnly) { - byte[] data = (byte[]) ProviderHelper.getGenericData( - this, KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri), - KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); - if (data != null) { - String fingerprint = PgpKeyHelper.convertFingerprintToHex(data); - content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; - } else { - Toast.makeText(getApplicationContext(), "Bad key selected!", - Toast.LENGTH_LONG).show(); - return; - } - } else { - // get public keyring as ascii armored string - long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); - ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString( - this, new long[]{masterKeyId}); - - content = keyringArmored.get(0); - - // Android will fail with android.os.TransactionTooLargeException if key is too big - // see http://www.lonestarprod.com/?p=34 - if (content.length() >= 86389) { - Toast.makeText(getApplicationContext(), R.string.key_too_big_for_sharing, - Toast.LENGTH_LONG).show(); - return; - } - } - - // let user choose application - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, content); - sendIntent.setType("text/plain"); - startActivity(Intent.createChooser(sendIntent, - getResources().getText(R.string.action_share_key_with))); - } - - private void shareKeyQrCode(Uri dataUri, boolean fingerprintOnly) { - ShareQrCodeDialogFragment dialog = ShareQrCodeDialogFragment.newInstance(dataUri, - fingerprintOnly); - dialog.show(getSupportFragmentManager(), "shareQrCodeDialog"); - } - - private void copyToClipboard(Uri dataUri) { - // get public keyring as ascii armored string - long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); - ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString( - this, new long[]{masterKeyId}); - - ClipboardReflection.copyToClipboard(this, keyringArmored.get(0)); - Toast.makeText(getApplicationContext(), R.string.key_copied_to_clipboard, Toast.LENGTH_LONG) - .show(); - } - - private void shareNfc() { - ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); - dialog.show(getSupportFragmentManager(), "shareNfcDialog"); - } - - private void deleteKey(Uri dataUri) { - // Message is received after key is deleted - Handler returnHandler = new Handler() { - @Override - public void handleMessage(Message message) { - setResult(RESULT_CANCELED); - finish(); - } - }; - - mExportHelper.deleteKey(dataUri, returnHandler); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case RESULT_CODE_LOOKUP_KEY: { - if (resultCode == Activity.RESULT_OK) { - // TODO: reload key??? move this into fragment? - } - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - - break; - } - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java deleted file mode 100644 index 6dc0413bb..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.annotation.TargetApi; -import android.nfc.NdefMessage; -import android.nfc.NdefRecord; -import android.nfc.NfcAdapter; -import android.nfc.NfcAdapter.CreateNdefMessageCallback; -import android.nfc.NfcAdapter.OnNdefPushCompleteCallback; -import android.nfc.NfcEvent; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.widget.Toast; - -import com.devspark.appmsg.AppMsg; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; - -@TargetApi(Build.VERSION_CODES.JELLY_BEAN) -public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMessageCallback, - OnNdefPushCompleteCallback { - - private NfcAdapter mNfcAdapter; - private byte[] mSharedKeyringBytes; - private static final int NFC_SENT = 1; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - initNfc(); - } - - /** - * NFC: Initialize NFC sharing if OS and device supports it - */ - private void initNfc() { - // check if NFC Beam is supported (>= Android 4.1) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - // Check for available NFC Adapter - mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - if (mNfcAdapter != null) { - // init nfc - // Register callback to set NDEF message - mNfcAdapter.setNdefPushMessageCallback(this, this); - // Register callback to listen for message-sent success - mNfcAdapter.setOnNdefPushCompleteCallback(this, this); - } - } - } - - /** - * NFC: Implementation for the CreateNdefMessageCallback interface - */ - @Override - public NdefMessage createNdefMessage(NfcEvent event) { - /** - * When a device receives a push with an AAR in it, the application specified in the AAR is - * guaranteed to run. The AAR overrides the tag dispatch system. You can add it back in to - * guarantee that this activity starts when receiving a beamed message. For now, this code - * uses the tag dispatch system. - */ - try { - // get public keyring as byte array - mSharedKeyringBytes = ProviderHelper.getPGPKeyRing(this, mDataUri).getEncoded(); - - NdefMessage msg = new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME, - mSharedKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME)); - return msg; - } catch(IOException e) { - Log.e(Constants.TAG, "Error parsing keyring", e); - return null; - } - } - - /** - * NFC: Implementation for the OnNdefPushCompleteCallback interface - */ - @Override - public void onNdefPushComplete(NfcEvent arg0) { - // A handler is needed to send messages to the activity when this - // callback occurs, because it happens from a binder thread - mNfcHandler.obtainMessage(NFC_SENT).sendToTarget(); - } - - /** - * NFC: This handler receives a message from onNdefPushComplete - */ - private final Handler mNfcHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case NFC_SENT: - AppMsg.makeText(ViewKeyActivityJB.this, R.string.nfc_successfull, - AppMsg.STYLE_INFO).show(); - break; - } - } - }; - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java deleted file mode 100644 index b738970f1..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.support.v4.widget.CursorAdapter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.TextView; - -import org.spongycastle.openpgp.PGPSignature; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; -import org.sufficientlysecure.keychain.util.Log; - -import se.emilsjolander.stickylistheaders.ApiLevelTooLowException; -import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; -import se.emilsjolander.stickylistheaders.StickyListHeadersListView; - - -public class ViewKeyCertsFragment extends Fragment - implements LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener { - - // These are the rows that we will retrieve. - static final String[] PROJECTION = new String[] { - Certs._ID, - Certs.MASTER_KEY_ID, - Certs.VERIFIED, - Certs.TYPE, - Certs.RANK, - Certs.KEY_ID_CERTIFIER, - Certs.USER_ID, - Certs.SIGNER_UID - }; - - // sort by our user id, - static final String SORT_ORDER = - Tables.CERTS + "." + Certs.RANK + " ASC, " - + Certs.VERIFIED + " DESC, " + Certs.TYPE + " DESC, " + Certs.SIGNER_UID + " ASC"; - - public static final String ARG_DATA_URI = "data_uri"; - - private StickyListHeadersListView mStickyList; - private CertListAdapter mAdapter; - - private Uri mDataUri; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.view_key_certs_fragment, container, false); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mStickyList = (StickyListHeadersListView) getActivity().findViewById(R.id.list); - - if (!getArguments().containsKey(ARG_DATA_URI)) { - Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); - getActivity().finish(); - return; - } - - Uri uri = getArguments().getParcelable(ARG_DATA_URI); - mDataUri = Certs.buildCertsUri(uri); - - mStickyList.setAreHeadersSticky(true); - mStickyList.setDrawingListUnderStickyHeader(false); - mStickyList.setFastScrollEnabled(true); - mStickyList.setOnItemClickListener(this); - - try { - mStickyList.setFastScrollAlwaysVisible(true); - } catch (ApiLevelTooLowException e) { - } - - mStickyList.setEmptyView(getActivity().findViewById(R.id.empty)); - - // TODO this view is made visible if no data is available - // mStickyList.setEmptyView(getActivity().findViewById(R.id.empty)); - - - // Create an empty adapter we will use to display the loaded data. - mAdapter = new CertListAdapter(getActivity(), null); - mStickyList.setAdapter(mAdapter); - - getLoaderManager().initLoader(0, null, this); - } - - @Override - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), mDataUri, PROJECTION, null, null, SORT_ORDER); - } - - @Override - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - mAdapter.swapCursor(data); - - mStickyList.setAdapter(mAdapter); - } - - /** - * On click on item, start key view activity - */ - @Override - public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { - if(view.getTag(R.id.tag_mki) != null) { - long masterKeyId = (Long) view.getTag(R.id.tag_mki); - long rank = (Long) view.getTag(R.id.tag_rank); - long certifierId = (Long) view.getTag(R.id.tag_certifierId); - - Intent viewIntent = new Intent(getActivity(), ViewCertActivity.class); - viewIntent.setData(Certs.buildCertsSpecificUri( - Long.toString(masterKeyId), Long.toString(rank), Long.toString(certifierId))); - startActivity(viewIntent); - } - } - - @Override - public void onLoaderReset(Loader<Cursor> loader) { - // This is called when the last Cursor provided to onLoadFinished() - // above is about to be closed. We need to make sure we are no - // longer using it. - mAdapter.swapCursor(null); - } - - /** - * Implements StickyListHeadersAdapter from library - */ - private class CertListAdapter extends CursorAdapter implements StickyListHeadersAdapter { - private LayoutInflater mInflater; - private int mIndexMasterKeyId, mIndexUserId, mIndexRank; - private int mIndexSignerKeyId, mIndexSignerUserId; - private int mIndexVerified, mIndexType; - - public CertListAdapter(Context context, Cursor c) { - super(context, c, 0); - - mInflater = LayoutInflater.from(context); - initIndex(c); - } - - @Override - public Cursor swapCursor(Cursor newCursor) { - initIndex(newCursor); - - 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) { - mIndexMasterKeyId = cursor.getColumnIndexOrThrow(Certs.MASTER_KEY_ID); - mIndexUserId = cursor.getColumnIndexOrThrow(Certs.USER_ID); - mIndexRank = cursor.getColumnIndexOrThrow(Certs.RANK); - mIndexType = cursor.getColumnIndexOrThrow(Certs.TYPE); - mIndexVerified = cursor.getColumnIndexOrThrow(Certs.VERIFIED); - mIndexSignerKeyId = cursor.getColumnIndexOrThrow(Certs.KEY_ID_CERTIFIER); - mIndexSignerUserId = cursor.getColumnIndexOrThrow(Certs.SIGNER_UID); - } - } - - /** - * Bind cursor data to the item list view - * <p/> - * NOTE: CursorAdapter already implements the ViewHolder pattern in its getView() method. - * Thus no ViewHolder is required here. - */ - @Override - public void bindView(View view, Context context, Cursor cursor) { - - // set name and stuff, common to both key types - TextView wSignerKeyId = (TextView) view.findViewById(R.id.signerKeyId); - TextView wSignerUserId = (TextView) view.findViewById(R.id.signerUserId); - TextView wSignStatus = (TextView) view.findViewById(R.id.signStatus); - - String signerKeyId = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexSignerKeyId)); - String signerUserId = cursor.getString(mIndexSignerUserId); - switch(cursor.getInt(mIndexType)) { - case PGPSignature.DEFAULT_CERTIFICATION: // 0x10 - wSignStatus.setText(R.string.cert_default); break; - case PGPSignature.NO_CERTIFICATION: // 0x11 - wSignStatus.setText(R.string.cert_none); break; - case PGPSignature.CASUAL_CERTIFICATION: // 0x12 - wSignStatus.setText(R.string.cert_casual); break; - case PGPSignature.POSITIVE_CERTIFICATION: // 0x13 - wSignStatus.setText(R.string.cert_positive); break; - case PGPSignature.CERTIFICATION_REVOCATION: // 0x30 - wSignStatus.setText(R.string.cert_revoke); break; - } - - wSignerUserId.setText(signerUserId); - wSignerKeyId.setText(signerKeyId); - - view.setTag(R.id.tag_mki, cursor.getLong(mIndexMasterKeyId)); - view.setTag(R.id.tag_rank, cursor.getLong(mIndexRank)); - view.setTag(R.id.tag_certifierId, cursor.getLong(mIndexSignerKeyId)); - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.view_key_certs_item, parent, false); - } - - /** - * Creates a new header view and binds the section headers to it. It uses the ViewHolder - * pattern. Most functionality is similar to getView() from Android's CursorAdapter. - * <p/> - * NOTE: The variables mDataValid and mCursor are available due to the super class - * CursorAdapter. - */ - @Override - public View getHeaderView(int position, View convertView, ViewGroup parent) { - HeaderViewHolder holder; - if (convertView == null) { - holder = new HeaderViewHolder(); - convertView = mInflater.inflate(R.layout.view_key_certs_header, parent, false); - holder.text = (TextView) convertView.findViewById(R.id.stickylist_header_text); - holder.count = (TextView) convertView.findViewById(R.id.certs_num); - convertView.setTag(holder); - } else { - holder = (HeaderViewHolder) convertView.getTag(); - } - - if (!mDataValid) { - // no data available at this point - Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); - return convertView; - } - - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("couldn't move cursor to position " + position); - } - - // set header text as first char in user id - String userId = mCursor.getString(mIndexUserId); - holder.text.setText(userId); - holder.count.setVisibility(View.GONE); - return convertView; - } - - /** - * Header IDs should be static, position=1 should always return the same Id that is. - */ - @Override - public long getHeaderId(int position) { - if (!mDataValid) { - // no data available at this point - Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); - return -1; - } - - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("couldn't move cursor to position " + position); - } - - // otherwise, return the first character of the name as ID - return mCursor.getInt(mIndexRank); - - // sort by the first four characters (should be enough I guess?) - // return ByteBuffer.wrap(userId.getBytes()).asLongBuffer().get(0); - } - - class HeaderViewHolder { - TextView text; - TextView count; - } - - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java deleted file mode 100644 index 6e96a338a..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.database.Cursor; -import android.graphics.Color; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.text.format.DateFormat; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.ListView; -import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter; -import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.Date; - - -public class ViewKeyMainFragment extends Fragment implements - LoaderManager.LoaderCallbacks<Cursor> { - - public static final String ARG_DATA_URI = "uri"; - - private LinearLayout mContainer; - private TextView mName; - private TextView mEmail; - private TextView mComment; - private TextView mAlgorithm; - private TextView mKeyId; - private TextView mExpiry; - private TextView mCreation; - private TextView mFingerprint; - private TextView mSecretKey; - private BootstrapButton mActionEdit; - private BootstrapButton mActionEncrypt; - private BootstrapButton mActionCertify; - - private ListView mUserIds; - private ListView mKeys; - - private static final int LOADER_ID_UNIFIED = 0; - private static final int LOADER_ID_USER_IDS = 1; - private static final int LOADER_ID_KEYS = 2; - - private ViewKeyUserIdsAdapter mUserIdsAdapter; - private ViewKeyKeysAdapter mKeysAdapter; - - private Uri mDataUri; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.view_key_main_fragment, container, false); - - mContainer = (LinearLayout) view.findViewById(R.id.container); - mName = (TextView) view.findViewById(R.id.name); - mEmail = (TextView) view.findViewById(R.id.email); - mComment = (TextView) view.findViewById(R.id.comment); - mKeyId = (TextView) view.findViewById(R.id.key_id); - mAlgorithm = (TextView) view.findViewById(R.id.algorithm); - mCreation = (TextView) view.findViewById(R.id.creation); - mExpiry = (TextView) view.findViewById(R.id.expiry); - mFingerprint = (TextView) view.findViewById(R.id.fingerprint); - mSecretKey = (TextView) view.findViewById(R.id.secret_key); - mUserIds = (ListView) view.findViewById(R.id.user_ids); - mKeys = (ListView) view.findViewById(R.id.keys); - mActionEdit = (BootstrapButton) view.findViewById(R.id.action_edit); - mActionEncrypt = (BootstrapButton) view.findViewById(R.id.action_encrypt); - mActionCertify = (BootstrapButton) view.findViewById(R.id.action_certify); - - return view; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); - if (dataUri == null) { - Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); - getActivity().finish(); - return; - } - - loadData(dataUri); - } - - private void loadData(Uri dataUri) { - if (dataUri.equals(mDataUri)) { - Log.d(Constants.TAG, "Same URI, no need to load the data again!"); - return; - } - - getActivity().setProgressBarIndeterminateVisibility(Boolean.TRUE); - mContainer.setVisibility(View.GONE); - - mDataUri = dataUri; - - Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); - - mActionEncrypt.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - encryptToContact(mDataUri); - } - }); - mActionCertify.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - certifyKey(mDataUri); - } - }); - - mUserIdsAdapter = new ViewKeyUserIdsAdapter(getActivity(), null, 0); - mUserIds.setAdapter(mUserIdsAdapter); - - mKeysAdapter = new ViewKeyKeysAdapter(getActivity(), null, 0); - mKeys.setAdapter(mKeysAdapter); - - // Prepare the loaders. Either re-connect with an existing ones, - // or start new ones. - getActivity().getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); - getActivity().getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); - getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this); - } - - static final String[] UNIFIED_PROJECTION = new String[] { - KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_SECRET, - KeyRings.USER_ID, KeyRings.FINGERPRINT, - KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY, - - }; - static final int INDEX_UNIFIED_MKI = 1; - static final int INDEX_UNIFIED_HAS_SECRET = 2; - static final int INDEX_UNIFIED_UID = 3; - static final int INDEX_UNIFIED_FINGERPRINT = 4; - static final int INDEX_UNIFIED_ALGORITHM = 5; - static final int INDEX_UNIFIED_KEY_SIZE = 6; - static final int INDEX_UNIFIED_CREATION = 7; - static final int INDEX_UNIFIED_EXPIRY = 8; - - static final String[] KEYS_PROJECTION = new String[] { - Keys._ID, - Keys.KEY_ID, Keys.RANK, Keys.ALGORITHM, Keys.KEY_SIZE, - Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT, Keys.CAN_SIGN, Keys.IS_REVOKED, - Keys.CREATION, Keys.EXPIRY, Keys.FINGERPRINT - }; - static final int KEYS_INDEX_CAN_ENCRYPT = 6; - - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - switch (id) { - case LOADER_ID_UNIFIED: { - Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); - } - case LOADER_ID_USER_IDS: { - Uri baseUri = UserIds.buildUserIdsUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, ViewKeyUserIdsAdapter.USER_IDS_PROJECTION, null, null, null); - } - case LOADER_ID_KEYS: { - Uri baseUri = Keys.buildKeysUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, null); - } - - default: - return null; - } - } - - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - /* TODO better error handling? May cause problems when a key is deleted, - * because the notification triggers faster than the activity closes. - */ - // Avoid NullPointerExceptions... - if(data.getCount() == 0) - return; - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - switch (loader.getId()) { - case LOADER_ID_UNIFIED: { - if (data.moveToFirst()) { - // get name, email, and comment from USER_ID - String[] mainUserId = PgpKeyHelper.splitUserId(data.getString(INDEX_UNIFIED_UID)); - if (mainUserId[0] != null) { - getActivity().setTitle(mainUserId[0]); - mName.setText(mainUserId[0]); - } else { - getActivity().setTitle(R.string.user_id_no_name); - mName.setText(R.string.user_id_no_name); - } - mEmail.setText(mainUserId[1]); - mComment.setText(mainUserId[2]); - - if (data.getInt(INDEX_UNIFIED_HAS_SECRET) != 0) { - mSecretKey.setTextColor(getResources().getColor(R.color.emphasis)); - mSecretKey.setText(R.string.secret_key_yes); - - // edit button - mActionEdit.setVisibility(View.VISIBLE); - mActionEdit.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); - editIntent.setData(mDataUri); - editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY); - startActivityForResult(editIntent, 0); - } - }); - } else { - mSecretKey.setTextColor(Color.BLACK); - mSecretKey.setText(getResources().getString(R.string.secret_key_no)); - - // certify button - mActionCertify.setVisibility(View.VISIBLE); - // edit button - mActionEdit.setVisibility(View.GONE); - } - - // get key id from MASTER_KEY_ID - long masterKeyId = data.getLong(INDEX_UNIFIED_MKI); - String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId); - mKeyId.setText(keyIdStr); - - // get creation date from CREATION - if (data.isNull(INDEX_UNIFIED_CREATION)) { - mCreation.setText(R.string.none); - } else { - Date creationDate = new Date(data.getLong(INDEX_UNIFIED_CREATION) * 1000); - - mCreation.setText( - DateFormat.getDateFormat(getActivity().getApplicationContext()).format( - creationDate)); - } - - // get expiry date from EXPIRY - if (data.isNull(INDEX_UNIFIED_EXPIRY)) { - mExpiry.setText(R.string.none); - } else { - Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); - - mExpiry.setText( - DateFormat.getDateFormat(getActivity().getApplicationContext()).format( - expiryDate)); - } - - String algorithmStr = PgpKeyHelper.getAlgorithmInfo( - data.getInt(INDEX_UNIFIED_ALGORITHM), data.getInt(INDEX_UNIFIED_KEY_SIZE)); - mAlgorithm.setText(algorithmStr); - - byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); - String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob); - mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint)); - - break; - } - } - - case LOADER_ID_USER_IDS: - mUserIdsAdapter.swapCursor(data); - break; - - case LOADER_ID_KEYS: - // hide encrypt button if no encryption key is available - boolean canEncrypt = false; - data.moveToFirst(); - do { - if (data.getInt(KEYS_INDEX_CAN_ENCRYPT) == 1) { - canEncrypt = true; - break; - } - } while (data.moveToNext()); - if (!canEncrypt) { - mActionEncrypt.setVisibility(View.GONE); - } - - mKeysAdapter.swapCursor(data); - break; - } - getActivity().setProgressBarIndeterminateVisibility(Boolean.FALSE); - mContainer.setVisibility(View.VISIBLE); - } - - /** - * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. - * We need to make sure we are no longer using it. - */ - public void onLoaderReset(Loader<Cursor> loader) { - switch (loader.getId()) { - case LOADER_ID_USER_IDS: - mUserIdsAdapter.swapCursor(null); - break; - case LOADER_ID_KEYS: - mKeysAdapter.swapCursor(null); - break; - } - } - - private void encryptToContact(Uri dataUri) { - // TODO preselect from uri? should be feasible without trivial query - long keyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri); - - long[] encryptionKeyIds = new long[]{ keyId }; - Intent intent = new Intent(getActivity(), EncryptActivity.class); - intent.setAction(EncryptActivity.ACTION_ENCRYPT); - intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); - // used instead of startActivity set actionbar based on callingPackage - startActivityForResult(intent, 0); - } - - private void certifyKey(Uri dataUri) { - Intent signIntent = new Intent(getActivity(), CertifyKeyActivity.class); - signIntent.setData(dataUri); - startActivity(signIntent); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java deleted file mode 100644 index 5f2aec4fe..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -/** - * The AsyncTaskResultWrapper is used to wrap a result from a AsyncTask (for example: Loader). - * You can pass the result and an exception in it if an error occurred. - * Concept found at: - * https://stackoverflow.com/questions/19593577/how-to-handle-errors-in-custom-asynctaskloader - * - * @param <T> - Typ of the result which is wrapped - */ -public class AsyncTaskResultWrapper<T> { - - private final T mResult; - private final Exception mError; - - public AsyncTaskResultWrapper(T result, Exception error) { - this.mResult = result; - this.mError = error; - } - - public T getResult() { - return mResult; - } - - public Exception getError() { - return mError; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java deleted file mode 100644 index a3ed08a4c..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.content.Context; -import android.database.Cursor; -import android.support.v4.widget.CursorAdapter; -import android.text.Spannable; -import android.text.style.ForegroundColorSpan; -import org.sufficientlysecure.keychain.R; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public abstract class HighlightQueryCursorAdapter extends CursorAdapter { - - private String mCurQuery; - - public HighlightQueryCursorAdapter(Context context, Cursor c, int flags) { - super(context, c, flags); - mCurQuery = null; - } - - public void setSearchQuery(String searchQuery) { - mCurQuery = searchQuery; - } - - public String getSearchQuery() { - return mCurQuery; - } - - protected Spannable highlightSearchQuery(String text) { - Spannable highlight = Spannable.Factory.getInstance().newSpannable(text); - - if (mCurQuery != null) { - Pattern pattern = Pattern.compile("(?i)" + mCurQuery); - Matcher matcher = pattern.matcher(text); - if (matcher.find()) { - highlight.setSpan( - new ForegroundColorSpan(mContext.getResources().getColor(R.color.emphasis)), - matcher.start(), - matcher.end(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - return highlight; - } else { - return highlight; - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java deleted file mode 100644 index f322ea980..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.Context; -import android.graphics.Color; -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.LinearLayout; -import android.widget.LinearLayout.LayoutParams; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; - -import java.util.ArrayList; -import java.util.List; - -public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> { - protected LayoutInflater mInflater; - protected Activity mActivity; - - protected List<ImportKeysListEntry> mData; - - static class ViewHolder { - public TextView mainUserId; - public TextView mainUserIdRest; - public TextView keyId; - public TextView fingerprint; - public TextView algorithm; - public TextView status; - } - - public ImportKeysAdapter(Activity activity) { - super(activity, -1); - mActivity = activity; - mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - @SuppressLint("NewApi") - public void setData(List<ImportKeysListEntry> data) { - clear(); - if (data != null) { - this.mData = data; - - // add data to extended ArrayAdapter - if (Build.VERSION.SDK_INT >= 11) { - addAll(data); - } else { - for (ImportKeysListEntry entry : data) { - add(entry); - } - } - } - } - - public List<ImportKeysListEntry> getData() { - return mData; - } - - public ArrayList<ImportKeysListEntry> getSelectedData() { - ArrayList<ImportKeysListEntry> selectedData = new ArrayList<ImportKeysListEntry>(); - for (ImportKeysListEntry entry : mData) { - if (entry.isSelected()) { - selectedData.add(entry); - } - } - return selectedData; - } - - @Override - public boolean hasStableIds() { - return true; - } - - public View getView(int position, View convertView, ViewGroup parent) { - ImportKeysListEntry entry = mData.get(position); - ViewHolder holder; - if (convertView == null) { - holder = new ViewHolder(); - convertView = mInflater.inflate(R.layout.import_keys_list_entry, null); - holder.mainUserId = (TextView) convertView.findViewById(R.id.mainUserId); - holder.mainUserIdRest = (TextView) convertView.findViewById(R.id.mainUserIdRest); - holder.keyId = (TextView) convertView.findViewById(R.id.keyId); - holder.fingerprint = (TextView) convertView.findViewById(R.id.fingerprint); - holder.algorithm = (TextView) convertView.findViewById(R.id.algorithm); - holder.status = (TextView) convertView.findViewById(R.id.status); - convertView.setTag(holder); - } else { - holder = (ViewHolder) convertView.getTag(); - } - // main user id - String userId = entry.userIds.get(0); - String[] userIdSplit = PgpKeyHelper.splitUserId(userId); - - // name - if (userIdSplit[0] != null) { - // show red user id if it is a secret key - if (entry.secretKey) { - userIdSplit[0] = mActivity.getString(R.string.secret_key) + " " + userIdSplit[0]; - holder.mainUserId.setTextColor(Color.RED); - } - holder.mainUserId.setText(userIdSplit[0]); - } else { - holder.mainUserId.setText(R.string.user_id_no_name); - } - - // email - if (userIdSplit[1] != null) { - holder.mainUserIdRest.setText(userIdSplit[1]); - holder.mainUserIdRest.setVisibility(View.VISIBLE); - } else { - holder.mainUserIdRest.setVisibility(View.GONE); - } - - holder.keyId.setText(entry.keyIdHex); - - if (entry.fingerPrintHex != null) { - holder.fingerprint.setText(PgpKeyHelper.colorizeFingerprint(entry.fingerPrintHex)); - holder.fingerprint.setVisibility(View.VISIBLE); - } else { - holder.fingerprint.setVisibility(View.GONE); - } - - holder.algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm); - - if (entry.revoked) { - holder.status.setText(R.string.revoked); - } else { - holder.status.setVisibility(View.GONE); - } - - LinearLayout ll = (LinearLayout) convertView.findViewById(R.id.list); - ll.removeAllViews(); - if (entry.userIds.size() == 1) { - ll.setVisibility(View.GONE); - } else { - boolean first = true; - boolean second = true; - for (String uid : entry.userIds) { - if (first) { - first = false; - continue; - } - if (!second) { - View sep = new View(mActivity); - sep.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 1)); - sep.setBackgroundResource(android.R.drawable.divider_horizontal_dark); - ll.addView(sep); - } - TextView uidView = (TextView) mInflater.inflate( - R.layout.import_keys_list_entry_user_id, null); - uidView.setText(uid); - ll.addView(uidView); - second = false; - } - } - - CheckBox cBox = (CheckBox) convertView.findViewById(R.id.selected); - cBox.setChecked(entry.isSelected()); - - return convertView; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java deleted file mode 100644 index 5631d40ea..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListEntry.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.os.Parcel; -import android.os.Parcelable; -import android.util.SparseArray; - -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.util.IterableIterator; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; - -public class ImportKeysListEntry implements Serializable, Parcelable { - private static final long serialVersionUID = -7797972103284992662L; - - public ArrayList<String> userIds; - public long keyId; - public String keyIdHex; - public boolean revoked; - public Date date; // TODO: not displayed - public String fingerPrintHex; - public int bitStrength; - public String algorithm; - public boolean secretKey; - - private boolean mSelected; - - private byte[] mBytes = new byte[]{}; - - public ImportKeysListEntry(ImportKeysListEntry b) { - this.userIds = b.userIds; - this.keyId = b.keyId; - this.revoked = b.revoked; - this.date = b.date; - this.fingerPrintHex = b.fingerPrintHex; - this.keyIdHex = b.keyIdHex; - this.bitStrength = b.bitStrength; - this.algorithm = b.algorithm; - this.secretKey = b.secretKey; - this.mSelected = b.mSelected; - this.mBytes = b.mBytes; - } - - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeStringList(userIds); - dest.writeLong(keyId); - dest.writeByte((byte) (revoked ? 1 : 0)); - dest.writeSerializable(date); - dest.writeString(fingerPrintHex); - dest.writeString(keyIdHex); - dest.writeInt(bitStrength); - dest.writeString(algorithm); - dest.writeByte((byte) (secretKey ? 1 : 0)); - dest.writeByte((byte) (mSelected ? 1 : 0)); - dest.writeInt(mBytes.length); - dest.writeByteArray(mBytes); - } - - public static final Creator<ImportKeysListEntry> CREATOR = new Creator<ImportKeysListEntry>() { - public ImportKeysListEntry createFromParcel(final Parcel source) { - ImportKeysListEntry vr = new ImportKeysListEntry(); - vr.userIds = new ArrayList<String>(); - source.readStringList(vr.userIds); - vr.keyId = source.readLong(); - vr.revoked = source.readByte() == 1; - vr.date = (Date) source.readSerializable(); - vr.fingerPrintHex = source.readString(); - vr.keyIdHex = source.readString(); - vr.bitStrength = source.readInt(); - vr.algorithm = source.readString(); - vr.secretKey = source.readByte() == 1; - vr.mSelected = source.readByte() == 1; - vr.mBytes = new byte[source.readInt()]; - source.readByteArray(vr.mBytes); - - return vr; - } - - public ImportKeysListEntry[] newArray(final int size) { - return new ImportKeysListEntry[size]; - } - }; - - public String getKeyIdHex() { - return keyIdHex; - } - - public byte[] getBytes() { - return mBytes; - } - - public void setBytes(byte[] bytes) { - this.mBytes = bytes; - } - - public boolean isSelected() { - return mSelected; - } - - public void setSelected(boolean selected) { - this.mSelected = selected; - } - - public long getKeyId() { - return keyId; - } - - public void setKeyId(long keyId) { - this.keyId = keyId; - } - - public void setKeyIdHex(String keyIdHex) { - this.keyIdHex = keyIdHex; - } - - public boolean isRevoked() { - return revoked; - } - - public void setRevoked(boolean revoked) { - this.revoked = revoked; - } - - public Date getDate() { - return date; - } - - public void setDate(Date date) { - this.date = date; - } - - public String getFingerPrintHex() { - return fingerPrintHex; - } - - public void setFingerPrintHex(String fingerPrintHex) { - this.fingerPrintHex = fingerPrintHex; - } - - public int getBitStrength() { - return bitStrength; - } - - public void setBitStrength(int bitStrength) { - this.bitStrength = bitStrength; - } - - public String getAlgorithm() { - return algorithm; - } - - public void setAlgorithm(String algorithm) { - this.algorithm = algorithm; - } - - public boolean isSecretKey() { - return secretKey; - } - - public void setSecretKey(boolean secretKey) { - this.secretKey = secretKey; - } - - public ArrayList<String> getUserIds() { - return userIds; - } - - public void setUserIds(ArrayList<String> userIds) { - this.userIds = userIds; - } - - /** - * Constructor for later querying from keyserver - */ - public ImportKeysListEntry() { - // keys from keyserver are always public keys - secretKey = false; - // do not select by default - mSelected = false; - userIds = new ArrayList<String>(); - } - - /** - * Constructor based on key object, used for import from NFC, QR Codes, files - */ - @SuppressWarnings("unchecked") - public ImportKeysListEntry(PGPKeyRing pgpKeyRing) { - // save actual key object into entry, used to import it later - try { - this.mBytes = pgpKeyRing.getEncoded(); - } catch (IOException e) { - Log.e(Constants.TAG, "IOException on pgpKeyRing.getEncoded()", e); - } - - // selected is default - this.mSelected = true; - - if (pgpKeyRing instanceof PGPSecretKeyRing) { - secretKey = true; - } else { - secretKey = false; - } - - userIds = new ArrayList<String>(); - for (String userId : new IterableIterator<String>(pgpKeyRing.getPublicKey().getUserIDs())) { - userIds.add(userId); - } - - this.keyId = pgpKeyRing.getPublicKey().getKeyID(); - this.keyIdHex = PgpKeyHelper.convertKeyIdToHex(keyId); - - this.revoked = pgpKeyRing.getPublicKey().isRevoked(); - this.fingerPrintHex = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey() - .getFingerprint()); - this.bitStrength = pgpKeyRing.getPublicKey().getBitStrength(); - final int algorithm = pgpKeyRing.getPublicKey().getAlgorithm(); - this.algorithm = getAlgorithmFromId(algorithm); - } - - /** - * Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a> - */ - private static final SparseArray<String> ALGORITHM_IDS = new SparseArray<String>() {{ - put(-1, "unknown"); // TODO: with resources - put(0, "unencrypted"); - put(PGPPublicKey.RSA_GENERAL, "RSA"); - put(PGPPublicKey.RSA_ENCRYPT, "RSA"); - put(PGPPublicKey.RSA_SIGN, "RSA"); - put(PGPPublicKey.ELGAMAL_ENCRYPT, "ElGamal"); - put(PGPPublicKey.ELGAMAL_GENERAL, "ElGamal"); - put(PGPPublicKey.DSA, "DSA"); - put(PGPPublicKey.EC, "ECC"); - put(PGPPublicKey.ECDSA, "ECC"); - put(PGPPublicKey.ECDH, "ECC"); - }}; - - /** - * Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a> - */ - public static String getAlgorithmFromId(int algorithmId) { - return (ALGORITHM_IDS.get(algorithmId) != null ? - ALGORITHM_IDS.get(algorithmId) : - ALGORITHM_IDS.get(-1)); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java deleted file mode 100644 index c9983213c..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.content.Context; -import android.support.v4.content.AsyncTaskLoader; -import org.spongycastle.openpgp.PGPKeyRing; -import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPUtil; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.PositionAwareInputStream; - -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.util.ArrayList; - -public class ImportKeysListLoader - extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { - - public static class FileHasNoContent extends Exception { - - } - - public static class NonPgpPart extends Exception { - private int mCount; - - public NonPgpPart(int count) { - this.mCount = count; - } - - public int getCount() { - return mCount; - } - } - - Context mContext; - - InputData mInputData; - - ArrayList<ImportKeysListEntry> mData = new ArrayList<ImportKeysListEntry>(); - AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper; - - public ImportKeysListLoader(Context context, InputData inputData) { - super(context); - this.mContext = context; - this.mInputData = inputData; - } - - @Override - public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() { - - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, null); - - if (mInputData == null) { - Log.e(Constants.TAG, "Input data is null!"); - return mEntryListWrapper; - } - - generateListOfKeyrings(mInputData); - - return mEntryListWrapper; - } - - @Override - protected void onReset() { - super.onReset(); - - // Ensure the loader is stopped - onStopLoading(); - } - - @Override - protected void onStartLoading() { - forceLoad(); - } - - @Override - protected void onStopLoading() { - cancelLoad(); - } - - @Override - public void deliverResult(AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) { - super.deliverResult(data); - } - - /** - * Reads all PGPKeyRing objects from input - * - * @param inputData - * @return - */ - private void generateListOfKeyrings(InputData inputData) { - - boolean isEmpty = true; - int nonPgpCounter = 0; - - PositionAwareInputStream progressIn = new PositionAwareInputStream( - inputData.getInputStream()); - - // need to have access to the bufferedInput, so we can reuse it for the possible - // PGPObject chunks after the first one, e.g. files with several consecutive ASCII - // armor blocks - BufferedInputStream bufferedInput = new BufferedInputStream(progressIn); - try { - - // read all available blocks... (asc files can contain many blocks with BEGIN END) - while (bufferedInput.available() > 0) { - isEmpty = false; - InputStream in = PGPUtil.getDecoderStream(bufferedInput); - PGPObjectFactory objectFactory = new PGPObjectFactory(in); - - // go through all objects in this block - Object obj; - while ((obj = objectFactory.nextObject()) != null) { - Log.d(Constants.TAG, "Found class: " + obj.getClass()); - - if (obj instanceof PGPKeyRing) { - PGPKeyRing newKeyring = (PGPKeyRing) obj; - addToData(newKeyring); - } else { - Log.e(Constants.TAG, "Object not recognized as PGPKeyRing!"); - nonPgpCounter++; - } - } - } - } catch (Exception e) { - Log.e(Constants.TAG, "Exception on parsing key file!", e); - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, e); - nonPgpCounter = 0; - } - - if (isEmpty) { - Log.e(Constants.TAG, "File has no content!", new FileHasNoContent()); - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> - (mData, new FileHasNoContent()); - } - - if (nonPgpCounter > 0) { - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> - (mData, new NonPgpPart(nonPgpCounter)); - } - } - - private void addToData(PGPKeyRing keyring) { - ImportKeysListEntry item = new ImportKeysListEntry(keyring); - mData.add(item); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java deleted file mode 100644 index 259e14319..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.content.Context; -import android.support.v4.content.AsyncTaskLoader; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.HkpKeyServer; -import org.sufficientlysecure.keychain.util.KeyServer; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.ArrayList; - -public class ImportKeysListServerLoader - extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { - Context mContext; - - String mServerQuery; - String mKeyServer; - - private ArrayList<ImportKeysListEntry> mEntryList = new ArrayList<ImportKeysListEntry>(); - private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper; - - public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) { - super(context); - mContext = context; - mServerQuery = serverQuery; - mKeyServer = keyServer; - } - - @Override - public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() { - - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null); - - if (mServerQuery == null) { - Log.e(Constants.TAG, "mServerQuery is null!"); - return mEntryListWrapper; - } - - if (mServerQuery.startsWith("0x") && mServerQuery.length() == 42) { - Log.d(Constants.TAG, "This search is based on a unique fingerprint. Enforce a fingerprint check!"); - queryServer(mServerQuery, mKeyServer, true); - } else { - queryServer(mServerQuery, mKeyServer, false); - } - - return mEntryListWrapper; - } - - @Override - protected void onReset() { - super.onReset(); - - // Ensure the loader is stopped - onStopLoading(); - } - - @Override - protected void onStartLoading() { - forceLoad(); - } - - @Override - protected void onStopLoading() { - cancelLoad(); - } - - @Override - public void deliverResult(AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) { - super.deliverResult(data); - } - - /** - * Query keyserver - */ - private void queryServer(String query, String keyServer, boolean enforceFingerprint) { - HkpKeyServer server = new HkpKeyServer(keyServer); - try { - ArrayList<ImportKeysListEntry> searchResult = server.search(query); - - mEntryList.clear(); - // add result to data - if (enforceFingerprint) { - String fingerprint = query.substring(2); - Log.d(Constants.TAG, "fingerprint: " + fingerprint); - // query must return only one result! - if (searchResult.size() > 0) { - ImportKeysListEntry uniqueEntry = searchResult.get(0); - /* - * set fingerprint explicitly after query - * to enforce a check when the key is imported by KeychainIntentService - */ - uniqueEntry.setFingerPrintHex(fingerprint); - uniqueEntry.setSelected(true); - mEntryList.add(uniqueEntry); - } - } else { - mEntryList.addAll(searchResult); - } - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null); - } catch (KeyServer.InsufficientQuery e) { - Log.e(Constants.TAG, "InsufficientQuery", e); - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e); - } catch (KeyServer.QueryException e) { - Log.e(Constants.TAG, "QueryException", e); - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e); - } catch (KeyServer.TooManyResponses e) { - Log.e(Constants.TAG, "TooManyResponses", e); - mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e); - } - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java deleted file mode 100644 index 5b5d316b6..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.content.Context; -import android.widget.ArrayAdapter; - -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; - -public class KeyValueSpinnerAdapter extends ArrayAdapter<String> { - private final HashMap<Integer, String> mData; - private final int[] mKeys; - private final String[] mValues; - - static <K, V extends Comparable<? super V>> SortedSet<Map.Entry<K, V>> entriesSortedByValues( - Map<K, V> map) { - SortedSet<Map.Entry<K, V>> sortedEntries = new TreeSet<Map.Entry<K, V>>( - new Comparator<Map.Entry<K, V>>() { - @Override - public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) { - return e1.getValue().compareTo(e2.getValue()); - } - }); - sortedEntries.addAll(map.entrySet()); - return sortedEntries; - } - - public KeyValueSpinnerAdapter(Context context, HashMap<Integer, String> objects) { - // To make the drop down a simple text box - super(context, android.R.layout.simple_spinner_item); - mData = objects; - - // To make the drop down view a radio button list - setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - - SortedSet<Map.Entry<Integer, String>> sorted = entriesSortedByValues(objects); - - // Assign hash keys with a position so that we can present and retrieve them - int i = 0; - mKeys = new int[mData.size()]; - mValues = new String[mData.size()]; - for (Map.Entry<Integer, String> entry : sorted) { - mKeys[i] = entry.getKey(); - mValues[i] = entry.getValue(); - i++; - } - } - - public int getCount() { - return mData.size(); - } - - /** - * Returns the value - */ - @Override - public String getItem(int position) { - // return the value based on the position. This is displayed in the list. - return mValues[position]; - } - - /** - * Returns item key - */ - public long getItemId(int position) { - // Return an id to represent the item. - - return mKeys[position]; - } - - /** - * Find position from key - */ - public int getPosition(long itemId) { - for (int i = 0; i < mKeys.length; i++) { - if ((int) itemId == mKeys[i]) { - return i; - } - } - return -1; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java deleted file mode 100644 index fd864eb09..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.content.Context; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentPagerAdapter; -import android.support.v7.app.ActionBarActivity; - -import java.util.ArrayList; - -public class PagerTabStripAdapter extends FragmentPagerAdapter { - private final Context mContext; - private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); - - static final class TabInfo { - public final Class<?> clss; - public final Bundle args; - public final String title; - - TabInfo(Class<?> clss, Bundle args, String title) { - this.clss = clss; - this.args = args; - this.title = title; - } - } - - public PagerTabStripAdapter(ActionBarActivity activity) { - super(activity.getSupportFragmentManager()); - mContext = activity; - } - - public void addTab(Class<?> clss, Bundle args, String title) { - TabInfo info = new TabInfo(clss, args, title); - mTabs.add(info); - notifyDataSetChanged(); - } - - @Override - public int getCount() { - return mTabs.size(); - } - - @Override - public Fragment getItem(int position) { - TabInfo info = mTabs.get(position); - return Fragment.instantiate(mContext, info.clss.getName(), info.args); - } - - @Override - public CharSequence getPageTitle(int position) { - return mTabs.get(position).title; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java deleted file mode 100644 index fbbb9caa4..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.content.Context; -import android.database.Cursor; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.ListView; -import android.widget.TextView; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; - - -public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter { - - protected int mKeyType; - - private LayoutInflater mInflater; - private ListView mListView; - - private int mIndexUserId; - private int mIndexMasterKeyId; - private int mIndexProjectionValid; - private int mIndexProjectionAvailable; - - public static final String PROJECTION_ROW_AVAILABLE = "available"; - public static final String PROJECTION_ROW_VALID = "valid"; - - public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView, - int keyType) { - super(context, c, flags); - - mInflater = LayoutInflater.from(context); - mListView = listView; - mKeyType = keyType; - initIndex(c); - } - - @Override - public Cursor swapCursor(Cursor newCursor) { - initIndex(newCursor); - - 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); - mIndexMasterKeyId = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID); - mIndexProjectionValid = cursor.getColumnIndexOrThrow(PROJECTION_ROW_VALID); - mIndexProjectionAvailable = cursor.getColumnIndexOrThrow(PROJECTION_ROW_AVAILABLE); - } - } - - public String getUserId(int position) { - mCursor.moveToPosition(position); - return mCursor.getString(mIndexUserId); - } - - public long getMasterKeyId(int position) { - mCursor.moveToPosition(position); - return mCursor.getLong(mIndexMasterKeyId); - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - boolean valid = cursor.getInt(mIndexProjectionValid) > 0; - - TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); - TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - TextView keyId = (TextView) view.findViewById(R.id.keyId); - TextView status = (TextView) view.findViewById(R.id.status); - - String userId = cursor.getString(mIndexUserId); - String[] userIdSplit = PgpKeyHelper.splitUserId(userId); - - if (userIdSplit[0] != null) { - mainUserId.setText(highlightSearchQuery(userIdSplit[0])); - } else { - mainUserId.setText(R.string.user_id_no_name); - } - if (userIdSplit[1] != null) { - mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1])); - } else { - mainUserIdRest.setText(""); - } - - // TODO: needed to key id to no? - keyId.setText(R.string.no_key); - long masterKeyId = cursor.getLong(mIndexMasterKeyId); - keyId.setText(PgpKeyHelper.convertKeyIdToHexShort(masterKeyId)); - - // TODO: needed to set unknown_status? - status.setText(R.string.unknown_status); - if (valid) { - if (mKeyType == Id.type.public_key) { - status.setText(R.string.can_encrypt); - } else { - status.setText(R.string.can_sign); - } - } else { - if (cursor.getInt(mIndexProjectionAvailable) > 0) { - // has some CAN_ENCRYPT keys, but col(ROW_VALID) = 0, so must be revoked or - // expired - status.setText(R.string.expired); - } else { - status.setText(R.string.no_key); - } - } - - CheckBox selected = (CheckBox) view.findViewById(R.id.selected); - if (mKeyType == Id.type.public_key) { - selected.setVisibility(View.VISIBLE); - - if (!valid) { - mListView.setItemChecked(cursor.getPosition(), false); - } - - selected.setChecked(mListView.isItemChecked(cursor.getPosition())); - selected.setEnabled(valid); - } else { - selected.setVisibility(View.GONE); - } - - status.setText(status.getText() + " "); - - view.setEnabled(valid); - mainUserId.setEnabled(valid); - mainUserIdRest.setEnabled(valid); - keyId.setEnabled(valid); - status.setEnabled(valid); - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.select_key_item, null); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java deleted file mode 100644 index 9ddfa90be..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.content.Context; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentStatePagerAdapter; -import android.support.v4.app.FragmentTransaction; -import android.support.v4.view.ViewPager; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; - -import java.util.ArrayList; - -public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.TabListener, - ViewPager.OnPageChangeListener { - private final Context mContext; - private final ActionBar mActionBar; - private final ViewPager mViewPager; - private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); - - static final class TabInfo { - public final Class<?> clss; - public final Bundle args; - - TabInfo(Class<?> clss, Bundle args) { - this.clss = clss; - this.args = args; - } - } - - public TabsAdapter(ActionBarActivity activity, ViewPager pager) { - super(activity.getSupportFragmentManager()); - mContext = activity; - mActionBar = activity.getSupportActionBar(); - mViewPager = pager; - mViewPager.setAdapter(this); - mViewPager.setOnPageChangeListener(this); - } - - public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args, boolean selected) { - TabInfo info = new TabInfo(clss, args); - tab.setTag(info); - tab.setTabListener(this); - mTabs.add(info); - mActionBar.addTab(tab, selected); - notifyDataSetChanged(); - } - - @Override - public int getCount() { - return mTabs.size(); - } - - @Override - public Fragment getItem(int position) { - TabInfo info = mTabs.get(position); - return Fragment.instantiate(mContext, info.clss.getName(), info.args); - } - - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - } - - public void onPageSelected(int position) { - mActionBar.setSelectedNavigationItem(position); - } - - public void onPageScrollStateChanged(int state) { - } - - public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { - Object tag = tab.getTag(); - for (int i = 0; i < mTabs.size(); i++) { - if (mTabs.get(i) == tag) { - mViewPager.setCurrentItem(i); - } - } - } - - public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { - } - - public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java deleted file mode 100644 index 64b735bfa..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyKeysAdapter.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.database.Cursor; -import android.support.v4.widget.CursorAdapter; -import android.text.format.DateFormat; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.OtherHelper; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; - -import java.util.Date; - -public class ViewKeyKeysAdapter 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 mIndexRevokedKey; - private int mIndexExpiry; - - private ColorStateList mDefaultTextColor; - - public ViewKeyKeysAdapter(Context context, Cursor c, int flags) { - super(context, c, flags); - - mInflater = LayoutInflater.from(context); - - initIndex(c); - } - - @Override - public Cursor swapCursor(Cursor newCursor) { - initIndex(newCursor); - - 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); - 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); - TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails); - TextView keyExpiry = (TextView) view.findViewById(R.id.keyExpiry); - ImageView masterKeyIcon = (ImageView) view.findViewById(R.id.ic_masterKey); - ImageView certifyIcon = (ImageView) view.findViewById(R.id.ic_certifyKey); - ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey); - ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey); - ImageView revokedKeyIcon = (ImageView) view.findViewById(R.id.ic_revokedKey); - - String keyIdStr = PgpKeyHelper.convertKeyIdToHexShort(cursor.getLong(mIndexKeyId)); - String algorithmStr = PgpKeyHelper.getAlgorithmInfo(cursor.getInt(mIndexAlgorithm), - cursor.getInt(mIndexKeySize)); - - keyId.setText(keyIdStr); - keyDetails.setText("(" + algorithmStr + ")"); - - if (cursor.getInt(mIndexRank) == 0) { - masterKeyIcon.setVisibility(View.INVISIBLE); - } else { - masterKeyIcon.setVisibility(View.VISIBLE); - } - - if (cursor.getInt(mIndexCanCertify) != 1) { - certifyIcon.setVisibility(View.GONE); - } else { - certifyIcon.setVisibility(View.VISIBLE); - } - - if (cursor.getInt(mIndexCanEncrypt) != 1) { - encryptIcon.setVisibility(View.GONE); - } else { - encryptIcon.setVisibility(View.VISIBLE); - } - - if (cursor.getInt(mIndexCanSign) != 1) { - signIcon.setVisibility(View.GONE); - } else { - signIcon.setVisibility(View.VISIBLE); - } - - boolean valid = true; - if (cursor.getInt(mIndexRevokedKey) > 0) { - revokedKeyIcon.setVisibility(View.VISIBLE); - - valid = false; - } else { - keyId.setTextColor(mDefaultTextColor); - keyDetails.setTextColor(mDefaultTextColor); - keyExpiry.setTextColor(mDefaultTextColor); - - revokedKeyIcon.setVisibility(View.GONE); - } - - if (!cursor.isNull(mIndexExpiry)) { - Date expiryDate = new Date(cursor.getLong(mIndexExpiry) * 1000); - - valid = valid && expiryDate.after(new Date()); - keyExpiry.setText("(" + - context.getString(R.string.label_expiry) + ": " + - DateFormat.getDateFormat(context).format(expiryDate) + ")"); - - keyExpiry.setVisibility(View.VISIBLE); - } else { - keyExpiry.setVisibility(View.GONE); - } - // if key is expired or revoked, strike through text - if (!valid) { - keyId.setText(OtherHelper.strikeOutText(keyId.getText())); - keyDetails.setText(OtherHelper.strikeOutText(keyDetails.getText())); - keyExpiry.setText(OtherHelper.strikeOutText(keyExpiry.getText())); - } - keyId.setEnabled(valid); - keyDetails.setEnabled(valid); - keyExpiry.setEnabled(valid); - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - View view = mInflater.inflate(R.layout.view_key_keys_item, null); - if (mDefaultTextColor == null) { - TextView keyId = (TextView) view.findViewById(R.id.keyId); - mDefaultTextColor = keyId.getTextColors(); - } - return view; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java deleted file mode 100644 index 09137f745..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ViewKeyUserIdsAdapter.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.adapter; - -import android.content.Context; -import android.database.Cursor; -import android.support.v4.widget.CursorAdapter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.ImageView; -import android.widget.TextView; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; - -import java.util.ArrayList; - -public class ViewKeyUserIdsAdapter extends CursorAdapter implements AdapterView.OnItemClickListener { - private LayoutInflater mInflater; - - private int mIndexUserId, mIndexRank; - private int mVerifiedId, mIsRevoked, mIsPrimary; - - private final ArrayList<Boolean> mCheckStates; - - public static final String[] USER_IDS_PROJECTION = new String[] { - UserIds._ID, UserIds.USER_ID, UserIds.RANK, - UserIds.VERIFIED, UserIds.IS_PRIMARY, UserIds.IS_REVOKED - }; - - public ViewKeyUserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes) { - super(context, c, flags); - - mInflater = LayoutInflater.from(context); - - mCheckStates = showCheckBoxes ? new ArrayList<Boolean>() : null; - - initIndex(c); - } - public ViewKeyUserIdsAdapter(Context context, Cursor c, int flags) { - this(context, c, flags, false); - } - - @Override - public Cursor swapCursor(Cursor newCursor) { - initIndex(newCursor); - if (mCheckStates != null) { - mCheckStates.clear(); - if (newCursor != null) { - int count = newCursor.getCount(); - mCheckStates.ensureCapacity(count); - // 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); - mCheckStates.add(verified != Certs.VERIFIED_SECRET); - } - } - } - - 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 vRank = (TextView) view.findViewById(R.id.rank); - TextView vUserId = (TextView) view.findViewById(R.id.userId); - TextView vAddress = (TextView) view.findViewById(R.id.address); - ImageView vVerified = (ImageView) view.findViewById(R.id.certified); - - if(cursor.getInt(mIsPrimary) > 0) { - vRank.setText("+"); - } else { - vRank.setText(Integer.toString(cursor.getInt(mIndexRank))); - } - - String[] userId = PgpKeyHelper.splitUserId(cursor.getString(mIndexUserId)); - if (userId[0] != null) { - vUserId.setText(userId[0]); - } else { - vUserId.setText(R.string.user_id_no_name); - } - vAddress.setText(userId[1]); - - if(cursor.getInt(mIsRevoked) > 0) { - vRank.setText(" "); - vVerified.setImageResource(android.R.drawable.presence_away); - } else { - int verified = cursor.getInt(mVerifiedId); - // TODO introduce own resources for this :) - if(verified == Certs.VERIFIED_SECRET) - vVerified.setImageResource(android.R.drawable.presence_online); - else if(verified == Certs.VERIFIED_SELF) - vVerified.setImageResource(android.R.drawable.presence_invisible); - else - vVerified.setImageResource(android.R.drawable.presence_busy); - } - - // don't care further if checkboxes aren't shown - if (mCheckStates == null) { - return; - } - - final CheckBox vCheckBox = (CheckBox) view.findViewById(R.id.checkBox); - final int position = cursor.getPosition(); - vCheckBox.setOnCheckedChangeListener(null); - vCheckBox.setChecked(mCheckStates.get(position)); - vCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean b) { - mCheckStates.set(position, b); - } - }); - vCheckBox.setClickable(false); - - } - - public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { - CheckBox box = ((CheckBox) view.findViewById(R.id.checkBox)); - if(box != null) { - box.toggle(); - } - } - - public ArrayList<String> getSelectedUserIds() { - ArrayList<String> result = new ArrayList<String>(); - for (int i = 0; i < mCheckStates.size(); i++) { - if (mCheckStates.get(i)) { - mCursor.moveToPosition(i); - result.add(mCursor.getString(mIndexUserId)); - } - } - return result; - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - View view = mInflater.inflate(R.layout.view_key_userids_item, null); - // only need to do this once ever, since mShowCheckBoxes is final - view.findViewById(R.id.checkBox).setVisibility(mCheckStates != null ? View.VISIBLE : View.GONE); - return view; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java deleted file mode 100644 index 20b70658c..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentActivity; -import org.sufficientlysecure.keychain.R; - -public class BadImportKeyDialogFragment extends DialogFragment { - private static final String ARG_BAD_IMPORT = "bad_import"; - - /** - * Creates a new instance of this Bad Import Key DialogFragment - * - * @param bad - * @return - */ - public static BadImportKeyDialogFragment newInstance(int bad) { - BadImportKeyDialogFragment frag = new BadImportKeyDialogFragment(); - Bundle args = new Bundle(); - - args.putInt(ARG_BAD_IMPORT, bad); - frag.setArguments(args); - - return frag; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final FragmentActivity activity = getActivity(); - final int badImport = getArguments().getInt(ARG_BAD_IMPORT); - - AlertDialog.Builder alert = new AlertDialog.Builder(activity); - alert.setIcon(R.drawable.ic_dialog_alert_holo_light); - alert.setTitle(R.string.warning); - alert.setMessage(activity.getResources() - .getQuantityString(R.plurals.bad_keys_encountered, badImport, badImport)); - alert.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - alert.setCancelable(true); - - return alert.create(); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java deleted file mode 100644 index ad558a81e..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentActivity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Spinner; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Choice; - -import java.util.ArrayList; - -public class CreateKeyDialogFragment extends DialogFragment { - - public interface OnAlgorithmSelectedListener { - public void onAlgorithmSelected(Choice algorithmChoice, int keySize); - } - - private static final String ARG_EDITOR_CHILD_COUNT = "child_count"; - - private int mNewKeySize; - private Choice mNewKeyAlgorithmChoice; - private OnAlgorithmSelectedListener mAlgorithmSelectedListener; - - public void setOnAlgorithmSelectedListener(OnAlgorithmSelectedListener listener) { - mAlgorithmSelectedListener = listener; - } - - public static CreateKeyDialogFragment newInstance(int mEditorChildCount) { - CreateKeyDialogFragment frag = new CreateKeyDialogFragment(); - Bundle args = new Bundle(); - - args.putInt(ARG_EDITOR_CHILD_COUNT, mEditorChildCount); - - frag.setArguments(args); - - return frag; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final FragmentActivity context = getActivity(); - final LayoutInflater mInflater; - - final int childCount = getArguments().getInt(ARG_EDITOR_CHILD_COUNT); - mInflater = context.getLayoutInflater(); - - AlertDialog.Builder dialog = new AlertDialog.Builder(context); - - View view = mInflater.inflate(R.layout.create_key_dialog, null); - dialog.setView(view); - dialog.setTitle(R.string.title_create_key); - - boolean wouldBeMasterKey = (childCount == 0); - - final Spinner algorithm = (Spinner) view.findViewById(R.id.create_key_algorithm); - ArrayList<Choice> choices = new ArrayList<Choice>(); - choices.add(new Choice(Id.choice.algorithm.dsa, getResources().getString( - R.string.dsa))); - if (!wouldBeMasterKey) { - choices.add(new Choice(Id.choice.algorithm.elgamal, getResources().getString( - R.string.elgamal))); - } - - choices.add(new Choice(Id.choice.algorithm.rsa, getResources().getString( - R.string.rsa))); - - ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(context, - android.R.layout.simple_spinner_item, choices); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - algorithm.setAdapter(adapter); - // make RSA the default - for (int i = 0; i < choices.size(); ++i) { - if (choices.get(i).getId() == Id.choice.algorithm.rsa) { - algorithm.setSelection(i); - break; - } - } - - final Spinner keySize = (Spinner) view.findViewById(R.id.create_key_size); - ArrayAdapter<CharSequence> keySizeAdapter = ArrayAdapter.createFromResource( - context, R.array.key_size_spinner_values, - android.R.layout.simple_spinner_item); - keySizeAdapter - .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - keySize.setAdapter(keySizeAdapter); - keySize.setSelection(3); // Default to 4096 for the key length - dialog.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface di, int id) { - di.dismiss(); - try { - final String selectedItem = (String) keySize.getSelectedItem(); - mNewKeySize = Integer.parseInt(selectedItem); - } catch (NumberFormatException e) { - mNewKeySize = 0; - } - - mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem(); - mAlgorithmSelectedListener.onAlgorithmSelected(mNewKeyAlgorithmChoice, mNewKeySize); - } - }); - - dialog.setCancelable(true); - dialog.setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface di, int id) { - di.dismiss(); - } - }); - - final AlertDialog alertDialog = dialog.create(); - - final AdapterView.OnItemSelectedListener weakRsaListener = new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - final Choice selectedAlgorithm = (Choice) algorithm.getSelectedItem(); - final int selectedKeySize = Integer.parseInt((String) keySize.getSelectedItem()); - final boolean isWeakRsa = (selectedAlgorithm.getId() == Id.choice.algorithm.rsa && - selectedKeySize <= 1024); - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(!isWeakRsa); - } - - @Override - public void onNothingSelected(AdapterView<?> parent) { - } - }; - - keySize.setOnItemSelectedListener(weakRsaListener); - algorithm.setOnItemSelectedListener(weakRsaListener); - - return alertDialog; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java deleted file mode 100644 index b4c38184c..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentActivity; -import android.widget.Toast; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; - -public class DeleteFileDialogFragment extends DialogFragment { - private static final String ARG_DELETE_FILE = "delete_file"; - - /** - * Creates new instance of this delete file dialog fragment - */ - public static DeleteFileDialogFragment newInstance(String deleteFile) { - DeleteFileDialogFragment frag = new DeleteFileDialogFragment(); - Bundle args = new Bundle(); - - args.putString(ARG_DELETE_FILE, deleteFile); - - frag.setArguments(args); - - return frag; - } - - /** - * Creates dialog - */ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final FragmentActivity activity = getActivity(); - - final String deleteFile = getArguments().getString(ARG_DELETE_FILE); - - AlertDialog.Builder alert = new AlertDialog.Builder(activity); - - - alert.setIcon(R.drawable.ic_dialog_alert_holo_light); - alert.setTitle(R.string.warning); - alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFile)); - - alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - - // Send all information needed to service to edit key in other thread - Intent intent = new Intent(activity, KeychainIntentService.class); - - // fill values for this action - Bundle data = new Bundle(); - - intent.setAction(KeychainIntentService.ACTION_DELETE_FILE_SECURELY); - data.putString(KeychainIntentService.DELETE_FILE, deleteFile); - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - ProgressDialogFragment deletingDialog = ProgressDialogFragment.newInstance( - getString(R.string.progress_deleting_securely), - ProgressDialog.STYLE_HORIZONTAL, - false, - null); - - // Message is received after deleting is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = - new KeychainIntentServiceHandler(activity, deletingDialog) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - Toast.makeText(activity, R.string.file_delete_successful, - Toast.LENGTH_SHORT).show(); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - deletingDialog.show(activity.getSupportFragmentManager(), "deletingDialog"); - - // start service with intent - activity.startService(intent); - } - }); - alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dismiss(); - } - }); - alert.setCancelable(true); - - return alert.create(); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java deleted file mode 100644 index 72ea4c013..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.app.AlertDialog; -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.support.v4.app.FragmentActivity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.CheckBox; -import android.widget.LinearLayout; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.HashMap; - -public class DeleteKeyDialogFragment extends DialogFragment { - private static final String ARG_MESSENGER = "messenger"; - private static final String ARG_DELETE_MASTER_KEY_IDS = "delete_master_key_ids"; - - public static final int MESSAGE_OKAY = 1; - public static final int MESSAGE_ERROR = 0; - - private boolean mIsSingleSelection = false; - - private TextView mMainMessage; - private CheckBox mCheckDeleteSecret; - private LinearLayout mDeleteSecretKeyView; - private View mInflateView; - - private Messenger mMessenger; - - /** - * Creates new instance of this delete file dialog fragment - */ - public static DeleteKeyDialogFragment newInstance(Messenger messenger, - long[] masterKeyIds) { - DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment(); - Bundle args = new Bundle(); - - args.putParcelable(ARG_MESSENGER, messenger); - args.putLongArray(ARG_DELETE_MASTER_KEY_IDS, masterKeyIds); - //We don't need the key type - - frag.setArguments(args); - - return frag; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - - final FragmentActivity activity = getActivity(); - mMessenger = getArguments().getParcelable(ARG_MESSENGER); - - final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS); - - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - - //Setup custom View to display in AlertDialog - LayoutInflater inflater = activity.getLayoutInflater(); - mInflateView = inflater.inflate(R.layout.view_key_delete_fragment, null); - builder.setView(mInflateView); - - mDeleteSecretKeyView = (LinearLayout) mInflateView.findViewById(R.id.deleteSecretKeyView); - mMainMessage = (TextView) mInflateView.findViewById(R.id.mainMessage); - mCheckDeleteSecret = (CheckBox) mInflateView.findViewById(R.id.checkDeleteSecret); - - builder.setTitle(R.string.warning); - - // If only a single key has been selected - if (masterKeyIds.length == 1) { - mIsSingleSelection = true; - - long masterKeyId = masterKeyIds[0]; - - HashMap<String, Object> data = ProviderHelper.getUnifiedData(activity, masterKeyId, new String[]{ - KeyRings.USER_ID, - KeyRings.HAS_SECRET - }, new int[] { ProviderHelper.FIELD_TYPE_STRING, ProviderHelper.FIELD_TYPE_INTEGER }); - String userId = (String) data.get(KeyRings.USER_ID); - boolean hasSecret = ((Long) data.get(KeyRings.HAS_SECRET)) == 1; - - // Hide the Checkbox and TextView since this is a single selection,user will be notified through message - mDeleteSecretKeyView.setVisibility(View.GONE); - // Set message depending on which key it is. - mMainMessage.setText(getString( - hasSecret ? R.string.secret_key_deletion_confirmation - : R.string.public_key_deletetion_confirmation, - userId)); - } else { - mDeleteSecretKeyView.setVisibility(View.VISIBLE); - mMainMessage.setText(R.string.key_deletion_confirmation_multi); - } - - builder.setIcon(R.drawable.ic_dialog_alert_holo_light); - builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - - boolean success = false; - for(long masterKeyId : masterKeyIds) { - int count = activity.getContentResolver().delete( - KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null - ); - success = count > 0; - } - if (success) { - sendMessageToHandler(MESSAGE_OKAY, null); - } else { - sendMessageToHandler(MESSAGE_ERROR, null); - } - dismiss(); - } - }); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - } - }); - - return builder.create(); - } - - /** - * 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/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java deleted file mode 100644 index a4285c8e9..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.support.v4.app.DialogFragment; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.TextView; -import com.beardedhen.androidbootstrap.BootstrapButton; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.FileHelper; -import org.sufficientlysecure.keychain.util.Log; - -public class FileDialogFragment extends DialogFragment { - private static final String ARG_MESSENGER = "messenger"; - private static final String ARG_TITLE = "title"; - private static final String ARG_MESSAGE = "message"; - private static final String ARG_DEFAULT_FILE = "default_file"; - private static final String ARG_CHECKBOX_TEXT = "checkbox_text"; - - public static final int MESSAGE_OKAY = 1; - - public static final String MESSAGE_DATA_FILENAME = "filename"; - public static final String MESSAGE_DATA_CHECKED = "checked"; - - private Messenger mMessenger; - - private EditText mFilename; - private BootstrapButton mBrowse; - private CheckBox mCheckBox; - private TextView mMessageTextView; - - private static final int REQUEST_CODE = 0x00007004; - - /** - * Creates new instance of this file dialog fragment - */ - public static FileDialogFragment newInstance(Messenger messenger, String title, String message, - String defaultFile, String checkboxText) { - FileDialogFragment frag = new FileDialogFragment(); - Bundle args = new Bundle(); - args.putParcelable(ARG_MESSENGER, messenger); - - args.putString(ARG_TITLE, title); - args.putString(ARG_MESSAGE, message); - args.putString(ARG_DEFAULT_FILE, defaultFile); - args.putString(ARG_CHECKBOX_TEXT, checkboxText); - - frag.setArguments(args); - - return frag; - } - - /** - * Creates dialog - */ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Activity activity = getActivity(); - - mMessenger = getArguments().getParcelable(ARG_MESSENGER); - - String title = getArguments().getString(ARG_TITLE); - String message = getArguments().getString(ARG_MESSAGE); - String defaultFile = getArguments().getString(ARG_DEFAULT_FILE); - String checkboxText = getArguments().getString(ARG_CHECKBOX_TEXT); - - LayoutInflater inflater = (LayoutInflater) activity - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - AlertDialog.Builder alert = new AlertDialog.Builder(activity); - alert.setTitle(title); - - View view = inflater.inflate(R.layout.file_dialog, null); - - mMessageTextView = (TextView) view.findViewById(R.id.message); - mMessageTextView.setText(message); - - mFilename = (EditText) view.findViewById(R.id.input); - mFilename.setText(defaultFile); - mBrowse = (BootstrapButton) view.findViewById(R.id.btn_browse); - mBrowse.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - // only .asc or .gpg files - // setting it to text/plain prevents Cynaogenmod's file manager from selecting asc - // or gpg types! - FileHelper.openFile(FileDialogFragment.this, mFilename.getText().toString(), "*/*", - REQUEST_CODE); - } - }); - - mCheckBox = (CheckBox) view.findViewById(R.id.checkbox); - if (checkboxText == null) { - mCheckBox.setEnabled(false); - mCheckBox.setVisibility(View.GONE); - } else { - mCheckBox.setEnabled(true); - mCheckBox.setVisibility(View.VISIBLE); - mCheckBox.setText(checkboxText); - } - - alert.setView(view); - - alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - - boolean checked = false; - if (mCheckBox.isEnabled()) { - checked = mCheckBox.isChecked(); - } - - // return resulting data back to activity - Bundle data = new Bundle(); - data.putString(MESSAGE_DATA_FILENAME, mFilename.getText().toString()); - data.putBoolean(MESSAGE_DATA_CHECKED, checked); - - sendMessageToHandler(MESSAGE_OKAY, data); - } - }); - - alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - } - }); - return alert.create(); - } - - /** - * Updates filename in dialog, normally called in onActivityResult in activity using the - * FileDialog - */ - private void setFilename(String filename) { - AlertDialog dialog = (AlertDialog) getDialog(); - EditText filenameEditText = (EditText) dialog.findViewById(R.id.input); - - if (filenameEditText != null) { - filenameEditText.setText(filename); - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode & 0xFFFF) { - case REQUEST_CODE: { - if (resultCode == Activity.RESULT_OK && data != null) { - try { - String path = data.getData().getPath(); - Log.d(Constants.TAG, "path=" + path); - - // set filename used in export/import dialogs - setFilename(path); - } catch (NullPointerException e) { - Log.e(Constants.TAG, "Nullpointer while retrieving path!", e); - } - } - - break; - } - - default: - super.onActivityResult(requestCode, resultCode, data); - - break; - } - } - - /** - * 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/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java deleted file mode 100644 index a3feab959..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentActivity; -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.EditText; -import android.widget.TextView; -import android.widget.TextView.OnEditorActionListener; -import android.widget.Toast; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPPrivateKey; -import org.spongycastle.openpgp.PGPSecretKey; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.util.Log; - -public class PassphraseDialogFragment extends DialogFragment implements OnEditorActionListener { - private static final String ARG_MESSENGER = "messenger"; - private static final String ARG_SECRET_KEY_ID = "secret_key_id"; - - public static final int MESSAGE_OKAY = 1; - public static final int MESSAGE_CANCEL = 2; - - public static final String MESSAGE_DATA_PASSPHRASE = "passphrase"; - - private Messenger mMessenger; - private EditText mPassphraseEditText; - private boolean mCanKB; - - /** - * Shows passphrase dialog to cache a new passphrase the user enters for using it later for - * encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks - * for a symmetric passphrase - */ - public static void show(FragmentActivity context, long keyId, Handler returnHandler) { - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(returnHandler); - - try { - PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(context, - messenger, keyId); - - passphraseDialog.show(context.getSupportFragmentManager(), "passphraseDialog"); - } catch (PgpGeneralException e) { - Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!"); - // send message to handler to start encryption directly - returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY); - } - } - - /** - * Creates new instance of this dialog fragment - * - * @param secretKeyId secret key id you want to use - * @param messenger to communicate back after caching the passphrase - * @return - * @throws PgpGeneralException - */ - public static PassphraseDialogFragment newInstance(Context context, Messenger messenger, - long secretKeyId) throws PgpGeneralException { - // check if secret key has a passphrase - if (!(secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none)) { - if (!PassphraseCacheService.hasPassphrase(context, secretKeyId)) { - throw new PgpGeneralException("No passphrase! No passphrase dialog needed!"); - } - } - - PassphraseDialogFragment frag = new PassphraseDialogFragment(); - Bundle args = new Bundle(); - args.putLong(ARG_SECRET_KEY_ID, secretKeyId); - args.putParcelable(ARG_MESSENGER, messenger); - - frag.setArguments(args); - - return frag; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - - /** - * Creates dialog - */ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Activity activity = getActivity(); - final long secretKeyId = getArguments().getLong(ARG_SECRET_KEY_ID); - mMessenger = getArguments().getParcelable(ARG_MESSENGER); - - AlertDialog.Builder alert = new AlertDialog.Builder(activity); - - alert.setTitle(R.string.title_authentication); - - final PGPSecretKey secretKey; - - if (secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none) { - secretKey = null; - alert.setMessage(R.string.passphrase_for_symmetric_encryption); - } else { - secretKey = ProviderHelper.getPGPSecretKeyRing(activity, secretKeyId).getSecretKey(); - - if (secretKey == null) { - alert.setTitle(R.string.title_key_not_found); - alert.setMessage(getString(R.string.key_not_found, secretKeyId)); - alert.setPositiveButton(android.R.string.ok, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dismiss(); - } - }); - alert.setCancelable(false); - mCanKB = false; - return alert.create(); - } - String userId = PgpKeyHelper.getMainUserIdSafe(activity, secretKey); - - Log.d(Constants.TAG, "User id: '" + userId + "'"); - alert.setMessage(getString(R.string.passphrase_for, userId)); - } - - LayoutInflater inflater = activity.getLayoutInflater(); - View view = inflater.inflate(R.layout.passphrase_dialog, null); - alert.setView(view); - - mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase); - - alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - long curKeyIndex = 1; - boolean keyOK = true; - String passphrase = mPassphraseEditText.getText().toString(); - long keyId; - PGPSecretKey clickSecretKey = secretKey; - - if (clickSecretKey != null) { - while (keyOK) { - if (clickSecretKey != null) { // check again for loop - try { - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - passphrase.toCharArray()); - PGPPrivateKey testKey = clickSecretKey - .extractPrivateKey(keyDecryptor); - if (testKey == null) { - if (!clickSecretKey.isMasterKey()) { - Toast.makeText(activity, - R.string.error_could_not_extract_private_key, - Toast.LENGTH_SHORT).show(); - - sendMessageToHandler(MESSAGE_CANCEL); - return; - } else { - clickSecretKey = PgpKeyHelper.getKeyNum(ProviderHelper - .getPGPSecretKeyRingWithKeyId(activity, secretKeyId), - curKeyIndex); - curKeyIndex++; // does post-increment work like C? - continue; - } - } else { - keyOK = false; - } - } catch (PGPException e) { - Toast.makeText(activity, R.string.wrong_passphrase, - Toast.LENGTH_SHORT).show(); - - sendMessageToHandler(MESSAGE_CANCEL); - return; - } - } else { - Toast.makeText(activity, R.string.error_could_not_extract_private_key, - Toast.LENGTH_SHORT).show(); - - sendMessageToHandler(MESSAGE_CANCEL); - return; // ran out of keys to try - } - } - keyId = secretKey.getKeyID(); - } else { - keyId = Id.key.symmetric; - } - - // cache the new passphrase - Log.d(Constants.TAG, "Everything okay! Caching entered passphrase"); - PassphraseCacheService.addCachedPassphrase(activity, keyId, passphrase); - if (!keyOK && clickSecretKey.getKeyID() != keyId) { - PassphraseCacheService.addCachedPassphrase(activity, clickSecretKey.getKeyID(), - passphrase); - } - - // also return passphrase back to activity - Bundle data = new Bundle(); - data.putString(MESSAGE_DATA_PASSPHRASE, passphrase); - - sendMessageToHandler(MESSAGE_OKAY, data); - } - }); - - alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - - mCanKB = true; - return alert.create(); - } - - @Override - public void onActivityCreated(Bundle arg0) { - super.onActivityCreated(arg0); - if (mCanKB) { - // request focus and open soft keyboard - mPassphraseEditText.requestFocus(); - getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE); - - mPassphraseEditText.setOnEditorActionListener(this); - } - } - - @Override - public void onCancel(DialogInterface dialog) { - super.onCancel(dialog); - - dismiss(); - sendMessageToHandler(MESSAGE_CANCEL); - } - - /** - * 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) { - Message msg = Message.obtain(); - msg.what = what; - - 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); - } - } - - /** - * 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/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java deleted file mode 100644 index 132a2ce86..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.app.Activity; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.content.DialogInterface.OnKeyListener; -import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.view.KeyEvent; -import org.sufficientlysecure.keychain.R; - -public class ProgressDialogFragment extends DialogFragment { - private static final String ARG_MESSAGE = "message"; - private static final String ARG_STYLE = "style"; - private static final String ARG_CANCELABLE = "cancelable"; - - private OnCancelListener mOnCancelListener; - - /** - * Creates new instance of this fragment - * - * @param message - * @param style - * @param cancelable - * @return - */ - public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable, - OnCancelListener onCancelListener) { - ProgressDialogFragment frag = new ProgressDialogFragment(); - Bundle args = new Bundle(); - args.putString(ARG_MESSAGE, message); - args.putInt(ARG_STYLE, style); - args.putBoolean(ARG_CANCELABLE, cancelable); - - frag.setArguments(args); - frag.mOnCancelListener = onCancelListener; - - return frag; - } - - /** - * Updates progress of dialog - * - * @param messageId - * @param progress - * @param max - */ - public void setProgress(int messageId, int progress, int max) { - setProgress(getString(messageId), progress, max); - } - - /** - * Updates progress of dialog - * - * @param progress - * @param max - */ - public void setProgress(int progress, int max) { - ProgressDialog dialog = (ProgressDialog) getDialog(); - - dialog.setProgress(progress); - dialog.setMax(max); - } - - /** - * Updates progress of dialog - * - * @param message - * @param progress - * @param max - */ - public void setProgress(String message, int progress, int max) { - ProgressDialog dialog = (ProgressDialog) getDialog(); - - dialog.setMessage(message); - dialog.setProgress(progress); - dialog.setMax(max); - } - - @Override - public void onCancel(DialogInterface dialog) { - super.onCancel(dialog); - - if (this.mOnCancelListener != null) { - this.mOnCancelListener.onCancel(dialog); - } - } - - /** - * Creates dialog - */ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Activity activity = getActivity(); - - ProgressDialog dialog = new ProgressDialog(activity); - dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - dialog.setCancelable(false); - dialog.setCanceledOnTouchOutside(false); - - String message = getArguments().getString(ARG_MESSAGE); - int style = getArguments().getInt(ARG_STYLE); - boolean cancelable = getArguments().getBoolean(ARG_CANCELABLE); - - dialog.setMessage(message); - dialog.setProgressStyle(style); - - if (cancelable) { - dialog.setButton(DialogInterface.BUTTON_NEGATIVE, - activity.getString(R.string.progress_cancel), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - } - - // Disable the back button - OnKeyListener keyListener = new OnKeyListener() { - - @Override - public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - return true; - } - return false; - } - - }; - dialog.setOnKeyListener(keyListener); - - return dialog; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java deleted file mode 100644 index ae61c1470..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.app.Activity; -import android.app.AlertDialog; -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.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.EditText; -import android.widget.TextView; -import android.widget.TextView.OnEditorActionListener; -import android.widget.Toast; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -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"; - - public static final int MESSAGE_OKAY = 1; - - public static final String MESSAGE_NEW_PASSPHRASE = "new_passphrase"; - - private Messenger mMessenger; - private EditText mPassphraseEditText; - private EditText mPassphraseAgainEditText; - - /** - * Creates new instance of this dialog fragment - * - * @param title title of dialog - * @param messenger to communicate back after setting the passphrase - * @return - */ - public static SetPassphraseDialogFragment newInstance(Messenger messenger, int title) { - SetPassphraseDialogFragment frag = new SetPassphraseDialogFragment(); - Bundle args = new Bundle(); - args.putInt(ARG_TITLE, title); - args.putParcelable(ARG_MESSENGER, messenger); - - 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); - - AlertDialog.Builder alert = new AlertDialog.Builder(activity); - - alert.setTitle(title); - alert.setMessage(R.string.enter_passphrase_twice); - - LayoutInflater inflater = activity.getLayoutInflater(); - View view = inflater.inflate(R.layout.passphrase_repeat_dialog, null); - alert.setView(view); - - mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase); - mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again); - - alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - - @Override - 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; - } - - // return resulting data back to activity - Bundle data = new Bundle(); - data.putString(MESSAGE_NEW_PASSPHRASE, passphrase1); - - sendMessageToHandler(MESSAGE_OKAY, data); - } - }); - - alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - } - }); - - return alert.create(); - } - - @Override - public void onActivityCreated(Bundle arg0) { - super.onActivityCreated(arg0); - - // request focus and open soft keyboard - mPassphraseEditText.requestFocus(); - getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE); - - mPassphraseAgainEditText.setOnEditorActionListener(this); - } - - /** - * 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/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java deleted file mode 100644 index 741530b1d..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.annotation.TargetApi; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.nfc.NfcAdapter; -import android.os.Build; -import android.os.Bundle; -import android.provider.Settings; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentActivity; -import org.sufficientlysecure.htmltextview.HtmlTextView; -import org.sufficientlysecure.keychain.R; - -@TargetApi(Build.VERSION_CODES.JELLY_BEAN) -public class ShareNfcDialogFragment extends DialogFragment { - - /** - * Creates new instance of this fragment - */ - public static ShareNfcDialogFragment newInstance() { - ShareNfcDialogFragment frag = new ShareNfcDialogFragment(); - - return frag; - } - - /** - * Creates dialog - */ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final FragmentActivity activity = getActivity(); - - AlertDialog.Builder alert = new AlertDialog.Builder(activity); - - alert.setTitle(R.string.share_nfc_dialog); - alert.setCancelable(true); - - alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - } - }); - - HtmlTextView textView = new HtmlTextView(getActivity()); - textView.setPadding(8, 8, 8, 8); - alert.setView(textView); - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - textView.setText(getString(R.string.error) + ": " - + getString(R.string.error_jelly_bean_needed)); - } else { - // check if NFC Adapter is available - NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity()); - if (nfcAdapter == null) { - textView.setText(getString(R.string.error) + ": " - + getString(R.string.error_nfc_needed)); - } else { - // nfc works... - textView.setHtmlFromRawResource(getActivity(), R.raw.nfc_beam_share); - - alert.setNegativeButton(R.string.menu_beam_preferences, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - Intent intentSettings = new Intent( - Settings.ACTION_NFCSHARING_SETTINGS); - startActivity(intentSettings); - } - }); - } - } - - // no flickering when clicking textview for Android < 4 - // aboutTextView.setTextColor(getResources().getColor(android.R.color.black)); - - return alert.create(); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java deleted file mode 100644 index b6ff139df..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.QrCodeUtils; - -import java.util.ArrayList; - -public class ShareQrCodeDialogFragment extends DialogFragment { - private static final String ARG_KEY_URI = "uri"; - private static final String ARG_FINGERPRINT_ONLY = "fingerprint_only"; - - private ImageView mImage; - private TextView mText; - - private boolean mFingerprintOnly; - - private ArrayList<String> mContentList; - private int mCounter; - - private static final int QR_CODE_SIZE = 1000; - - /** - * Creates new instance of this dialog fragment - */ - public static ShareQrCodeDialogFragment newInstance(Uri dataUri, boolean fingerprintOnly) { - ShareQrCodeDialogFragment frag = new ShareQrCodeDialogFragment(); - Bundle args = new Bundle(); - args.putParcelable(ARG_KEY_URI, dataUri); - args.putBoolean(ARG_FINGERPRINT_ONLY, fingerprintOnly); - - frag.setArguments(args); - - return frag; - } - - /** - * Creates dialog - */ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Activity activity = getActivity(); - - Uri dataUri = getArguments().getParcelable(ARG_KEY_URI); - mFingerprintOnly = getArguments().getBoolean(ARG_FINGERPRINT_ONLY); - - AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); - - alert.setTitle(R.string.share_qr_code_dialog_title); - - LayoutInflater inflater = activity.getLayoutInflater(); - View view = inflater.inflate(R.layout.share_qr_code_dialog, null); - alert.setView(view); - - mImage = (ImageView) view.findViewById(R.id.share_qr_code_dialog_image); - mText = (TextView) view.findViewById(R.id.share_qr_code_dialog_text); - - String content = null; - if (mFingerprintOnly) { - alert.setPositiveButton(R.string.btn_okay, null); - - byte[] blob = (byte[]) ProviderHelper.getGenericData( - getActivity(), KeyRings.buildUnifiedKeyRingUri(dataUri), - KeyRings.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); - if(blob == null) { - // TODO error handling?! - return null; - } - - String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob); - mText.setText(getString(R.string.share_qr_code_dialog_fingerprint_text) + " " + fingerprint); - content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; - setQrCode(content); - } else { - mText.setText(R.string.share_qr_code_dialog_start); - - // TODO works, but - long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri); - // get public keyring as ascii armored string - ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString( - getActivity(), new long[] { masterKeyId }); - - // TODO: binary? - - content = keyringArmored.get(0); - - // OnClickListener are set in onResume to prevent automatic dismissing of Dialogs - // http://bit.ly/O5vfaR - alert.setPositiveButton(R.string.btn_next, null); - alert.setNegativeButton(android.R.string.cancel, null); - - mContentList = splitString(content, 1000); - - // start with first - mCounter = 0; - updatePartsQrCode(); - } - - return alert.create(); - } - - @Override - public void onResume() { - super.onResume(); - - if (!mFingerprintOnly) { - AlertDialog alertDialog = (AlertDialog) getDialog(); - final Button backButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE); - final Button nextButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); - - backButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mCounter > 0) { - mCounter--; - updatePartsQrCode(); - updateDialog(backButton, nextButton); - } else { - dismiss(); - } - } - }); - nextButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - - if (mCounter < mContentList.size() - 1) { - mCounter++; - updatePartsQrCode(); - updateDialog(backButton, nextButton); - } else { - dismiss(); - } - } - }); - } - } - - private void updatePartsQrCode() { - // Content: <counter>,<size>,<content> - setQrCode(mCounter + "," + mContentList.size() + "," + mContentList.get(mCounter)); - } - - private void setQrCode(String data) { - mImage.setImageBitmap(QrCodeUtils.getQRCodeBitmap(data, QR_CODE_SIZE)); - } - - private void updateDialog(Button backButton, Button nextButton) { - if (mCounter == 0) { - backButton.setText(android.R.string.cancel); - } else { - backButton.setText(R.string.btn_back); - } - if (mCounter == mContentList.size() - 1) { - nextButton.setText(android.R.string.ok); - } else { - nextButton.setText(R.string.btn_next); - } - - mText.setText(getResources().getString(R.string.share_qr_code_dialog_progress, - mCounter + 1, mContentList.size())); - } - - /** - * Split String by number of characters - * - * @param text - * @param size - * @return - */ - private ArrayList<String> splitString(String text, int size) { - ArrayList<String> strings = new ArrayList<String>(); - int index = 0; - while (index < text.length()) { - strings.add(text.substring(index, Math.min(index + size, text.length()))); - index += size; - } - - return strings; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/Editor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/Editor.java deleted file mode 100644 index 7b21c189d..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/Editor.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -public interface Editor { - public interface EditorListener { - public void onDeleted(Editor editor, boolean wasNewItem); - public void onEdited(); - } - - public void setEditorListener(EditorListener listener); - public boolean needsSaving(); -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java deleted file mode 100644 index da29f808a..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.content.Context; -import android.util.AttributeSet; -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. - * <p/> - * from - * http://stackoverflow.com/questions/2419246/how-do-i-create-a-listview-thats-not-in-a-scrollview- - * or-has-the-scrollview-dis - */ -public class FixedListView extends ListView { - - public FixedListView(Context context) { - super(context); - } - - public FixedListView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - public FixedListView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // Calculate height of the entire list by providing a very large - // height hint. But do not use the highest 2 bits of this integer; - // those are reserved for the MeasureSpec mode. - int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); - super.onMeasure(widthMeasureSpec, expandSpec); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java deleted file mode 100644 index 6b2f3bf06..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.content.Context; -import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.widget.LinearLayout; -import android.widget.TextView; -import com.beardedhen.androidbootstrap.FontAwesomeText; -import org.sufficientlysecure.keychain.R; - -/** - * Class representing a LinearLayout that can fold and hide it's content when pressed - * To use just add the following to your xml layout - - <org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - custom:foldedLabel="@string/TEXT_TO_DISPLAY_WHEN_FOLDED" - custom:unFoldedLabel="@string/TEXT_TO_DISPLAY_WHEN_UNFOLDED" - custom:foldedIcon="ICON_NAME_FROM_FontAwesomeText_TO_USE_WHEN_FOLDED" - custom:unFoldedIcon="ICON_NAME_FROM_FontAwesomeText_TO_USE_WHEN_UNFOLDED"> - - <include layout="@layout/ELEMENTS_TO_BE_FOLDED"/> - - </org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout> - - */ -public class FoldableLinearLayout extends LinearLayout { - - private FontAwesomeText mFoldableIcon; - private boolean mFolded; - private boolean mHasMigrated = false; - private Integer mShortAnimationDuration = null; - private TextView mFoldableTextView = null; - private LinearLayout mFoldableContainer = null; - private View mFoldableLayout = null; - - private String mFoldedIconName; - private String mUnFoldedIconName; - private String mFoldedLabel; - private String mUnFoldedLabel; - - public FoldableLinearLayout(Context context) { - super(context); - processAttributes(context, null); - } - - public FoldableLinearLayout(Context context, AttributeSet attrs) { - super(context, attrs); - processAttributes(context, attrs); - } - - public FoldableLinearLayout(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs); - processAttributes(context, attrs); - } - - /** - * Load given attributes to inner variables, - * @param context - * @param attrs - */ - private void processAttributes(Context context, AttributeSet attrs) { - if (attrs != null) { - TypedArray a = context.obtainStyledAttributes(attrs, - R.styleable.FoldableLinearLayout, 0, 0); - mFoldedIconName = a.getString(R.styleable.FoldableLinearLayout_foldedIcon); - mUnFoldedIconName = a.getString(R.styleable.FoldableLinearLayout_unFoldedIcon); - mFoldedLabel = a.getString(R.styleable.FoldableLinearLayout_foldedLabel); - mUnFoldedLabel = a.getString(R.styleable.FoldableLinearLayout_unFoldedLabel); - a.recycle(); - } - // If any attribute isn't found then set a default one - mFoldedIconName = (mFoldedIconName == null) ? "fa-chevron-right" : mFoldedIconName; - mUnFoldedIconName = (mUnFoldedIconName == null) ? "fa-chevron-down" : mUnFoldedIconName; - mFoldedLabel = (mFoldedLabel == null) ? context.getString(R.id.none) : mFoldedLabel; - mUnFoldedLabel = (mUnFoldedLabel == null) ? context.getString(R.id.none) : mUnFoldedLabel; - } - - @Override - protected void onFinishInflate() { - // if the migration has already happened - // there is no need to move any children - if (!mHasMigrated) { - migrateChildrenToContainer(); - mHasMigrated = true; - } - - initialiseInnerViews(); - - super.onFinishInflate(); - } - - /** - * Migrates Child views as declared in xml to the inner foldableContainer - */ - private void migrateChildrenToContainer() { - // Collect children of FoldableLinearLayout as declared in XML - int childNum = getChildCount(); - View[] children = new View[childNum]; - - for (int i = 0; i < childNum; i++) { - children[i] = getChildAt(i); - } - if (children[0].getId() == R.id.foldableControl) { - - } - - // remove all of them from FoldableLinearLayout - detachAllViewsFromParent(); - - // Inflate the inner foldable_linearlayout.xml - LayoutInflater inflator = (LayoutInflater) getContext().getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - - mFoldableLayout = inflator.inflate(R.layout.foldable_linearlayout, this, true); - mFoldableContainer = (LinearLayout) mFoldableLayout.findViewById(R.id.foldableContainer); - - // Push previously collected children into foldableContainer. - for (int i = 0; i < childNum; i++) { - addView(children[i]); - } - } - - private void initialiseInnerViews() { - mFoldableIcon = (FontAwesomeText) mFoldableLayout.findViewById(R.id.foldableIcon); - mFoldableIcon.setIcon(mFoldedIconName); - mFoldableTextView = (TextView) mFoldableLayout.findViewById(R.id.foldableText); - mFoldableTextView.setText(mFoldedLabel); - - // retrieve and cache the system's short animation time - mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime); - - LinearLayout foldableControl = (LinearLayout) mFoldableLayout.findViewById(R.id.foldableControl); - foldableControl.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - mFolded = !mFolded; - if (mFolded) { - mFoldableIcon.setIcon(mUnFoldedIconName); - mFoldableContainer.setVisibility(View.VISIBLE); - AlphaAnimation animation = new AlphaAnimation(0f, 1f); - animation.setDuration(mShortAnimationDuration); - mFoldableContainer.startAnimation(animation); - mFoldableTextView.setText(mUnFoldedLabel); - - } else { - mFoldableIcon.setIcon(mFoldedIconName); - AlphaAnimation animation = new AlphaAnimation(1f, 0f); - animation.setDuration(mShortAnimationDuration); - animation.setAnimationListener(new Animation.AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { } - - @Override - public void onAnimationEnd(Animation animation) { - // making sure that at the end the container is completely removed from view - mFoldableContainer.setVisibility(View.GONE); - } - - @Override - public void onAnimationRepeat(Animation animation) { } - }); - mFoldableContainer.startAnimation(animation); - mFoldableTextView.setText(mFoldedLabel); - } - } - }); - - } - - /** - * Adds provided child view to foldableContainer View - * @param child - */ - @Override - public void addView(View child) { - if (mFoldableContainer != null) { - mFoldableContainer.addView(child); - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/IntegerListPreference.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/IntegerListPreference.java deleted file mode 100644 index 6e1e4c678..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/IntegerListPreference.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.content.Context; -import android.preference.ListPreference; -import android.util.AttributeSet; - -/** - * A list preference which persists its values as integers instead of strings. Code reading the - * values should use {@link android.content.SharedPreferences#getInt}. When using XML-declared - * arrays for entry values, the arrays should be regular string arrays containing valid integer - * values. - * - * @author Rodrigo Damazio - */ -public class IntegerListPreference extends ListPreference { - - public IntegerListPreference(Context context) { - super(context); - - verifyEntryValues(null); - } - - public IntegerListPreference(Context context, AttributeSet attrs) { - super(context, attrs); - - verifyEntryValues(null); - } - - @Override - public void setEntryValues(CharSequence[] entryValues) { - CharSequence[] oldValues = getEntryValues(); - super.setEntryValues(entryValues); - verifyEntryValues(oldValues); - } - - @Override - public void setEntryValues(int entryValuesResId) { - CharSequence[] oldValues = getEntryValues(); - super.setEntryValues(entryValuesResId); - verifyEntryValues(oldValues); - } - - @Override - protected String getPersistedString(String defaultReturnValue) { - // During initial load, there's no known default value - int defaultIntegerValue = Integer.MIN_VALUE; - if (defaultReturnValue != null) { - defaultIntegerValue = Integer.parseInt(defaultReturnValue); - } - - // When the list preference asks us to read a string, instead read an - // integer. - int value = getPersistedInt(defaultIntegerValue); - return Integer.toString(value); - } - - @Override - protected boolean persistString(String value) { - // When asked to save a string, instead save an integer - return persistInt(Integer.parseInt(value)); - } - - private void verifyEntryValues(CharSequence[] oldValues) { - CharSequence[] entryValues = getEntryValues(); - if (entryValues == null) { - return; - } - - for (CharSequence entryValue : entryValues) { - try { - Integer.parseInt(entryValue.toString()); - } catch (NumberFormatException nfe) { - super.setEntryValues(oldValues); - throw nfe; - } - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java deleted file mode 100644 index c7bd1c987..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.annotation.TargetApi; -import android.app.DatePickerDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.text.format.DateUtils; -import android.util.AttributeSet; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.DatePicker; -import android.widget.LinearLayout; -import android.widget.TableLayout; -import android.widget.TableRow; -import android.widget.TextView; - -import com.beardedhen.androidbootstrap.BootstrapButton; - -import org.spongycastle.bcpg.sig.KeyFlags; -import org.spongycastle.openpgp.PGPPublicKey; -import org.spongycastle.openpgp.PGPSecretKey; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.util.Choice; - -import java.text.DateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.TimeZone; -import java.util.Vector; - -public class KeyEditor extends LinearLayout implements Editor, OnClickListener { - private PGPSecretKey mKey; - - private EditorListener mEditorListener = null; - - private boolean mIsMasterKey; - BootstrapButton mDeleteButton; - TextView mAlgorithm; - TextView mKeyId; - TextView mCreationDate; - BootstrapButton mExpiryDateButton; - GregorianCalendar mCreatedDate; - GregorianCalendar mExpiryDate; - GregorianCalendar mOriginalExpiryDate = null; - CheckBox mChkCertify; - CheckBox mChkSign; - CheckBox mChkEncrypt; - CheckBox mChkAuthenticate; - int mUsage; - int mOriginalUsage; - boolean mIsNewKey; - - private CheckBox.OnCheckedChangeListener mCheckChanged = new CheckBox.OnCheckedChangeListener() - { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) - { - if (mEditorListener != null) { - mEditorListener.onEdited(); - } - } - }; - - - private int mDatePickerResultCount = 0; - private DatePickerDialog.OnDateSetListener mExpiryDateSetListener = - new DatePickerDialog.OnDateSetListener() { - public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { - // Note: Ignore results after the first one - android sends multiples. - if (mDatePickerResultCount++ == 0) { - GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - date.set(year, monthOfYear, dayOfMonth); - if (mOriginalExpiryDate != null) { - long numDays = (date.getTimeInMillis() / 86400000) - - (mOriginalExpiryDate.getTimeInMillis() / 86400000); - if (numDays == 0) { - setExpiryDate(mOriginalExpiryDate); - } else { - setExpiryDate(date); - } - } else { - setExpiryDate(date); - } - if (mEditorListener != null) { - mEditorListener.onEdited(); - } - } - } - }; - - public KeyEditor(Context context) { - super(context); - } - - public KeyEditor(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - setDrawingCacheEnabled(true); - setAlwaysDrawnWithCacheEnabled(true); - - mAlgorithm = (TextView) findViewById(R.id.algorithm); - mKeyId = (TextView) findViewById(R.id.keyId); - mCreationDate = (TextView) findViewById(R.id.creation); - mExpiryDateButton = (BootstrapButton) findViewById(R.id.expiry); - - mDeleteButton = (BootstrapButton) findViewById(R.id.delete); - mDeleteButton.setOnClickListener(this); - mChkCertify = (CheckBox) findViewById(R.id.chkCertify); - mChkCertify.setOnCheckedChangeListener(mCheckChanged); - mChkSign = (CheckBox) findViewById(R.id.chkSign); - mChkSign.setOnCheckedChangeListener(mCheckChanged); - mChkEncrypt = (CheckBox) findViewById(R.id.chkEncrypt); - mChkEncrypt.setOnCheckedChangeListener(mCheckChanged); - mChkAuthenticate = (CheckBox) findViewById(R.id.chkAuthenticate); - mChkAuthenticate.setOnCheckedChangeListener(mCheckChanged); - - setExpiryDate(null); - - mExpiryDateButton.setOnClickListener(new OnClickListener() { - @TargetApi(11) - public void onClick(View v) { - GregorianCalendar date = mExpiryDate; - if (date == null) { - date = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - } - /* - * Using custom DatePickerDialog which overrides the setTitle because - * the DatePickerDialog title is buggy (unix warparound bug). - * See: https://code.google.com/p/android/issues/detail?id=49066 - */ - DatePickerDialog dialog = new ExpiryDatePickerDialog(getContext(), - mExpiryDateSetListener, date.get(Calendar.YEAR), date.get(Calendar.MONTH), - date.get(Calendar.DAY_OF_MONTH)); - mDatePickerResultCount = 0; - dialog.setCancelable(true); - dialog.setButton(Dialog.BUTTON_NEGATIVE, - getContext().getString(R.string.btn_no_date), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - // Note: Ignore results after the first one - android sends multiples. - if (mDatePickerResultCount++ == 0) { - setExpiryDate(null); - if (mEditorListener != null) { - mEditorListener.onEdited(); - } - } - } - }); - - // setCalendarViewShown() is supported from API 11 onwards. - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { - // Hide calendarView in tablets because of the unix warparound bug. - dialog.getDatePicker().setCalendarViewShown(false); - } - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { - if (dialog != null && mCreatedDate != null) { - dialog.getDatePicker() - .setMinDate( - mCreatedDate.getTime().getTime() + DateUtils.DAY_IN_MILLIS); - } else { - //When created date isn't available - dialog.getDatePicker().setMinDate(date.getTime().getTime() + DateUtils.DAY_IN_MILLIS); - } - } - - dialog.show(); - } - }); - - super.onFinishInflate(); - } - - public void setCanBeEdited(boolean canBeEdited) { - if (!canBeEdited) { - mDeleteButton.setVisibility(View.INVISIBLE); - mExpiryDateButton.setEnabled(false); - mChkSign.setEnabled(false); //certify is always disabled - mChkEncrypt.setEnabled(false); - mChkAuthenticate.setEnabled(false); - } - } - - public void setValue(PGPSecretKey key, boolean isMasterKey, int usage, boolean isNewKey) { - mKey = key; - - mIsMasterKey = isMasterKey; - if (mIsMasterKey) { - mDeleteButton.setVisibility(View.INVISIBLE); - } - - mAlgorithm.setText(PgpKeyHelper.getAlgorithmInfo(key)); - String keyIdStr = PgpKeyHelper.convertKeyIdToHex(key.getKeyID()); - mKeyId.setText(keyIdStr); - - Vector<Choice> choices = new Vector<Choice>(); - boolean isElGamalKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT); - boolean isDSAKey = (key.getPublicKey().getAlgorithm() == PGPPublicKey.DSA); - if (isElGamalKey) { - mChkSign.setVisibility(View.INVISIBLE); - TableLayout table = (TableLayout) findViewById(R.id.table_keylayout); - TableRow row = (TableRow) findViewById(R.id.row_sign); - table.removeView(row); - } - if (isDSAKey) { - mChkEncrypt.setVisibility(View.INVISIBLE); - TableLayout table = (TableLayout) findViewById(R.id.table_keylayout); - TableRow row = (TableRow) findViewById(R.id.row_encrypt); - table.removeView(row); - } - if (!mIsMasterKey) { - mChkCertify.setVisibility(View.INVISIBLE); - TableLayout table = (TableLayout) findViewById(R.id.table_keylayout); - TableRow row = (TableRow) findViewById(R.id.row_certify); - table.removeView(row); - } else { - TextView mLabelUsage2 = (TextView) findViewById(R.id.label_usage2); - mLabelUsage2.setVisibility(View.INVISIBLE); - } - - int selectId = 0; - mIsNewKey = isNewKey; - if (isNewKey) { - mUsage = usage; - mChkCertify.setChecked((usage & KeyFlags.CERTIFY_OTHER) == KeyFlags.CERTIFY_OTHER); - mChkSign.setChecked((usage & KeyFlags.SIGN_DATA) == KeyFlags.SIGN_DATA); - mChkEncrypt.setChecked(((usage & KeyFlags.ENCRYPT_COMMS) == KeyFlags.ENCRYPT_COMMS) || - ((usage & KeyFlags.ENCRYPT_STORAGE) == KeyFlags.ENCRYPT_STORAGE)); - mChkAuthenticate.setChecked((usage & KeyFlags.AUTHENTICATION) == KeyFlags.AUTHENTICATION); - } else { - mUsage = PgpKeyHelper.getKeyUsage(key); - mOriginalUsage = mUsage; - if (key.isMasterKey()) { - mChkCertify.setChecked(PgpKeyHelper.isCertificationKey(key)); - } - mChkSign.setChecked(PgpKeyHelper.isSigningKey(key)); - mChkEncrypt.setChecked(PgpKeyHelper.isEncryptionKey(key)); - mChkAuthenticate.setChecked(PgpKeyHelper.isAuthenticationKey(key)); - } - - GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - cal.setTime(PgpKeyHelper.getCreationDate(key)); - setCreatedDate(cal); - cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - Date expiryDate = PgpKeyHelper.getExpiryDate(key); - if (expiryDate == null) { - setExpiryDate(null); - } else { - cal.setTime(PgpKeyHelper.getExpiryDate(key)); - setExpiryDate(cal); - mOriginalExpiryDate = cal; - } - - } - - public PGPSecretKey getValue() { - return mKey; - } - - public void onClick(View v) { - final ViewGroup parent = (ViewGroup) getParent(); - if (v == mDeleteButton) { - parent.removeView(this); - if (mEditorListener != null) { - mEditorListener.onDeleted(this, mIsNewKey); - } - } - } - - public void setEditorListener(EditorListener listener) { - mEditorListener = listener; - } - - private void setCreatedDate(GregorianCalendar date) { - mCreatedDate = date; - if (date == null) { - mCreationDate.setText(getContext().getString(R.string.none)); - } else { - mCreationDate.setText(DateFormat.getDateInstance().format(date.getTime())); - } - } - - private void setExpiryDate(GregorianCalendar date) { - mExpiryDate = date; - if (date == null) { - mExpiryDateButton.setText(getContext().getString(R.string.none)); - } else { - mExpiryDateButton.setText(DateFormat.getDateInstance().format(date.getTime())); - } - } - - public GregorianCalendar getExpiryDate() { - return mExpiryDate; - } - - public int getUsage() { - mUsage = (mUsage & ~KeyFlags.CERTIFY_OTHER) | - (mChkCertify.isChecked() ? KeyFlags.CERTIFY_OTHER : 0); - mUsage = (mUsage & ~KeyFlags.SIGN_DATA) | - (mChkSign.isChecked() ? KeyFlags.SIGN_DATA : 0); - mUsage = (mUsage & ~KeyFlags.ENCRYPT_COMMS) | - (mChkEncrypt.isChecked() ? KeyFlags.ENCRYPT_COMMS : 0); - mUsage = (mUsage & ~KeyFlags.ENCRYPT_STORAGE) | - (mChkEncrypt.isChecked() ? KeyFlags.ENCRYPT_STORAGE : 0); - mUsage = (mUsage & ~KeyFlags.AUTHENTICATION) | - (mChkAuthenticate.isChecked() ? KeyFlags.AUTHENTICATION : 0); - - return mUsage; - } - - public boolean needsSaving() { - if (mIsNewKey) { - return true; - } - - boolean retval = (getUsage() != mOriginalUsage); - - boolean dateChanged; - boolean mOEDNull = (mOriginalExpiryDate == null); - boolean mEDNull = (mExpiryDate == null); - if (mOEDNull != mEDNull) { - dateChanged = true; - } else { - if (mOEDNull) { - //both null, no change - dateChanged = false; - } else { - dateChanged = ((mExpiryDate.compareTo(mOriginalExpiryDate)) != 0); - } - } - retval |= dateChanged; - - return retval; - } - - public boolean getIsNewKey() { - return mIsNewKey; - } -} - -class ExpiryDatePickerDialog extends DatePickerDialog { - - public ExpiryDatePickerDialog(Context context, OnDateSetListener callBack, - int year, int monthOfYear, int dayOfMonth) { - super(context, callBack, year, monthOfYear, dayOfMonth); - } - - //Set permanent title. - public void setTitle(CharSequence title) { - super.setTitle(getContext().getString(R.string.expiry_date_dialog_title)); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java deleted file mode 100644 index 171763672..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyServerEditor.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.TextView; -import com.beardedhen.androidbootstrap.BootstrapButton; -import org.sufficientlysecure.keychain.R; - -public class KeyServerEditor extends LinearLayout implements Editor, OnClickListener { - private EditorListener mEditorListener = null; - - BootstrapButton mDeleteButton; - TextView mServer; - - public KeyServerEditor(Context context) { - super(context); - } - - public KeyServerEditor(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onFinishInflate() { - setDrawingCacheEnabled(true); - setAlwaysDrawnWithCacheEnabled(true); - - mServer = (TextView) findViewById(R.id.server); - - mDeleteButton = (BootstrapButton) findViewById(R.id.delete); - mDeleteButton.setOnClickListener(this); - - super.onFinishInflate(); - } - - public void setValue(String value) { - mServer.setText(value); - } - - public String getValue() { - return mServer.getText().toString().trim(); - } - - public void onClick(View v) { - final ViewGroup parent = (ViewGroup) getParent(); - if (v == mDeleteButton) { - parent.removeView(this); - if (mEditorListener != null) { - mEditorListener.onDeleted(this, false); - } - } - } - - @Override - public boolean needsSaving() { - return false; - } - - public void setEditorListener(EditorListener listener) { - mEditorListener = listener; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java deleted file mode 100644 index fb59cd3b7..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.support.v7.app.ActionBarActivity; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.TextView; -import com.beardedhen.androidbootstrap.BootstrapButton; - -import org.spongycastle.openpgp.PGPKeyFlags; -import org.spongycastle.openpgp.PGPSecretKey; - -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.ui.dialog.CreateKeyDialogFragment; -import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; -import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; -import org.sufficientlysecure.keychain.util.Choice; - -import java.util.ArrayList; -import java.util.List; -import java.util.Vector; - -public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Editor { - private LayoutInflater mInflater; - private BootstrapButton mPlusButton; - private ViewGroup mEditors; - private TextView mTitle; - private int mType = 0; - private EditorListener mEditorListener = null; - - private Choice mNewKeyAlgorithmChoice; - private int mNewKeySize; - private boolean mOldItemDeleted = false; - private ArrayList<String> mDeletedIDs = new ArrayList<String>(); - private ArrayList<PGPSecretKey> mDeletedKeys = new ArrayList<PGPSecretKey>(); - private boolean mCanBeEdited = true; - - private ActionBarActivity mActivity; - - private ProgressDialogFragment mGeneratingDialog; - - public void setEditorListener(EditorListener listener) { - mEditorListener = listener; - } - - public SectionView(Context context) { - super(context); - mActivity = (ActionBarActivity) context; - } - - public SectionView(Context context, AttributeSet attrs) { - super(context, attrs); - mActivity = (ActionBarActivity) context; - } - - public ViewGroup getEditors() { - return mEditors; - } - - public void setType(int type) { - mType = type; - switch (type) { - case Id.type.user_id: { - mTitle.setText(R.string.section_user_ids); - break; - } - - case Id.type.key: { - mTitle.setText(R.string.section_keys); - break; - } - - default: { - break; - } - } - } - - public void setCanBeEdited(boolean canBeEdited) { - mCanBeEdited = canBeEdited; - if (!mCanBeEdited) { - mPlusButton.setVisibility(View.INVISIBLE); - } - } - - /** - * {@inheritDoc} - */ - @Override - protected void onFinishInflate() { - mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - setDrawingCacheEnabled(true); - setAlwaysDrawnWithCacheEnabled(true); - - mPlusButton = (BootstrapButton) findViewById(R.id.plusbutton); - mPlusButton.setOnClickListener(this); - - mEditors = (ViewGroup) findViewById(R.id.editors); - mTitle = (TextView) findViewById(R.id.title); - - updateEditorsVisible(); - super.onFinishInflate(); - } - - /** - * {@inheritDoc} - */ - public void onDeleted(Editor editor, boolean wasNewItem) { - mOldItemDeleted |= !wasNewItem; - if (mOldItemDeleted) { - if (mType == Id.type.user_id) { - mDeletedIDs.add(((UserIdEditor) editor).getOriginalID()); - } else if (mType == Id.type.key) { - mDeletedKeys.add(((KeyEditor) editor).getValue()); - } - } - this.updateEditorsVisible(); - if (mEditorListener != null) { - mEditorListener.onEdited(); - } - } - - @Override - public void onEdited() { - if (mEditorListener != null) { - mEditorListener.onEdited(); - } - } - - protected void updateEditorsVisible() { - final boolean hasChildren = mEditors.getChildCount() > 0; - mEditors.setVisibility(hasChildren ? View.VISIBLE : View.GONE); - } - - public boolean needsSaving() { - //check each view for needs saving, take account of deleted items - boolean ret = mOldItemDeleted; - for (int i = 0; i < mEditors.getChildCount(); ++i) { - Editor editor = (Editor) mEditors.getChildAt(i); - ret |= editor.needsSaving(); - if (mType == Id.type.user_id) { - ret |= ((UserIdEditor) editor).primarySwapped(); - } - } - return ret; - } - - public boolean primaryChanged() { - boolean ret = false; - for (int i = 0; i < mEditors.getChildCount(); ++i) { - Editor editor = (Editor) mEditors.getChildAt(i); - if (mType == Id.type.user_id) { - ret |= ((UserIdEditor) editor).primarySwapped(); - } - } - return ret; - } - - public String getOriginalPrimaryID() { - //NB: this will have to change when we change how Primary IDs are chosen, and so we need to be - // careful about where Master key capabilities are stored... multiple primaries and - // revoked ones make this harder than the simple case we are continuing to assume here - for (int i = 0; i < mEditors.getChildCount(); ++i) { - Editor editor = (Editor) mEditors.getChildAt(i); - if (mType == Id.type.user_id) { - if (((UserIdEditor) editor).getIsOriginallyMainUserID()) { - return ((UserIdEditor) editor).getOriginalID(); - } - } - } - return null; - } - - public ArrayList<String> getOriginalIDs() { - ArrayList<String> orig = new ArrayList<String>(); - if (mType == Id.type.user_id) { - for (int i = 0; i < mEditors.getChildCount(); ++i) { - UserIdEditor editor = (UserIdEditor) mEditors.getChildAt(i); - if (editor.isMainUserId()) { - orig.add(0, editor.getOriginalID()); - } else { - orig.add(editor.getOriginalID()); - } - } - return orig; - } else { - return null; - } - } - - public ArrayList<String> getDeletedIDs() { - return mDeletedIDs; - } - - public ArrayList<PGPSecretKey> getDeletedKeys() { - return mDeletedKeys; - } - - public List<Boolean> getNeedsSavingArray() { - ArrayList<Boolean> mList = new ArrayList<Boolean>(); - for (int i = 0; i < mEditors.getChildCount(); ++i) { - Editor editor = (Editor) mEditors.getChildAt(i); - mList.add(editor.needsSaving()); - } - return mList; - } - - public List<Boolean> getNewIDFlags() { - ArrayList<Boolean> mList = new ArrayList<Boolean>(); - for (int i = 0; i < mEditors.getChildCount(); ++i) { - UserIdEditor editor = (UserIdEditor) mEditors.getChildAt(i); - if (editor.isMainUserId()) { - mList.add(0, editor.getIsNewID()); - } else { - mList.add(editor.getIsNewID()); - } - } - return mList; - } - - public List<Boolean> getNewKeysArray() { - ArrayList<Boolean> mList = new ArrayList<Boolean>(); - if (mType == Id.type.key) { - for (int i = 0; i < mEditors.getChildCount(); ++i) { - KeyEditor editor = (KeyEditor) mEditors.getChildAt(i); - mList.add(editor.getIsNewKey()); - } - } - return mList; - } - - /** - * {@inheritDoc} - */ - public void onClick(View v) { - if (mCanBeEdited) { - switch (mType) { - case Id.type.user_id: { - UserIdEditor view = (UserIdEditor) mInflater.inflate( - R.layout.edit_key_user_id_item, mEditors, false); - view.setEditorListener(this); - view.setValue("", mEditors.getChildCount() == 0, true); - mEditors.addView(view); - if (mEditorListener != null) { - mEditorListener.onEdited(); - } - break; - } - - case Id.type.key: { - CreateKeyDialogFragment mCreateKeyDialogFragment = - CreateKeyDialogFragment.newInstance(mEditors.getChildCount()); - mCreateKeyDialogFragment - .setOnAlgorithmSelectedListener( - new CreateKeyDialogFragment.OnAlgorithmSelectedListener() { - @Override - public void onAlgorithmSelected(Choice algorithmChoice, int keySize) { - mNewKeyAlgorithmChoice = algorithmChoice; - mNewKeySize = keySize; - createKey(); - } - }); - mCreateKeyDialogFragment.show(mActivity.getSupportFragmentManager(), "createKeyDialog"); - break; - } - - default: { - break; - } - } - this.updateEditorsVisible(); - } - } - - public void setUserIds(Vector<String> list) { - if (mType != Id.type.user_id) { - return; - } - - mEditors.removeAllViews(); - for (String userId : list) { - UserIdEditor view = (UserIdEditor) mInflater.inflate(R.layout.edit_key_user_id_item, - mEditors, false); - view.setEditorListener(this); - view.setValue(userId, mEditors.getChildCount() == 0, false); - view.setCanBeEdited(mCanBeEdited); - mEditors.addView(view); - } - - this.updateEditorsVisible(); - } - - public void setKeys(Vector<PGPSecretKey> list, Vector<Integer> usages, boolean newKeys) { - if (mType != Id.type.key) { - return; - } - - mEditors.removeAllViews(); - - // go through all keys and set view based on them - for (int i = 0; i < list.size(); i++) { - KeyEditor view = (KeyEditor) mInflater.inflate(R.layout.edit_key_key_item, mEditors, - false); - view.setEditorListener(this); - boolean isMasterKey = (mEditors.getChildCount() == 0); - view.setValue(list.get(i), isMasterKey, usages.get(i), newKeys); - view.setCanBeEdited(mCanBeEdited); - mEditors.addView(view); - } - - this.updateEditorsVisible(); - } - - private void createKey() { - // Send all information needed to service to edit key in other thread - final Intent intent = new Intent(mActivity, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_GENERATE_KEY); - - // fill values for this action - Bundle data = new Bundle(); - Boolean isMasterKey; - - String passphrase; - if (mEditors.getChildCount() > 0) { - PGPSecretKey masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue(); - passphrase = PassphraseCacheService - .getCachedPassphrase(mActivity, masterKey.getKeyID()); - isMasterKey = false; - } else { - passphrase = ""; - isMasterKey = true; - } - data.putBoolean(KeychainIntentService.GENERATE_KEY_MASTER_KEY, isMasterKey); - data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passphrase); - data.putInt(KeychainIntentService.GENERATE_KEY_ALGORITHM, mNewKeyAlgorithmChoice.getId()); - data.putInt(KeychainIntentService.GENERATE_KEY_KEY_SIZE, mNewKeySize); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // show progress dialog - mGeneratingDialog = ProgressDialogFragment.newInstance( - getResources().getQuantityString(R.plurals.progress_generating, 1), - ProgressDialog.STYLE_SPINNER, - true, - new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - mActivity.stopService(intent); - } - }); - - // Message is received after generating is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(mActivity, - mGeneratingDialog) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get new key from data bundle returned from service - Bundle data = message.getData(); - PGPSecretKey newKey = (PGPSecretKey) PgpConversionHelper - .BytesToPGPSecretKey(data - .getByteArray(KeychainIntentService.RESULT_NEW_KEY)); - addGeneratedKeyToView(newKey); - } - } - }; - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - mGeneratingDialog.show(mActivity.getSupportFragmentManager(), "dialog"); - - // start service with intent - mActivity.startService(intent); - } - - private void addGeneratedKeyToView(PGPSecretKey newKey) { - // add view with new key - KeyEditor view = (KeyEditor) mInflater.inflate(R.layout.edit_key_key_item, - mEditors, false); - view.setEditorListener(SectionView.this); - int usage = 0; - if (mEditors.getChildCount() == 0) { - usage = PGPKeyFlags.CAN_CERTIFY; - } - view.setValue(newKey, newKey.isMasterKey(), usage, true); - mEditors.addView(view); - SectionView.this.updateEditorsVisible(); - if (mEditorListener != null) { - mEditorListener.onEdited(); - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java deleted file mode 100644 index 937a48e48..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UnderlineTextView.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2013 Eric Frohnhoefer - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.widget.TextView; - -/** - * Copied from StickyListHeaders lib example - * - * @author Eric Frohnhoefer - */ -public class UnderlineTextView extends TextView { - private final Paint mPaint = new Paint(); - private int mUnderlineHeight = 0; - - public UnderlineTextView(Context context) { - this(context, null); - } - - public UnderlineTextView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public UnderlineTextView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - init(context, attrs); - } - - private void init(Context context, AttributeSet attrs) { - Resources r = getResources(); - mUnderlineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, - r.getDisplayMetrics()); - } - - @Override - public void setPadding(int left, int top, int right, int bottom) { - super.setPadding(left, top, right, bottom + mUnderlineHeight); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - // Draw the underline the same color as the text - mPaint.setColor(getTextColors().getDefaultColor()); - canvas.drawRect(0, getHeight() - mUnderlineHeight, getWidth(), getHeight(), mPaint); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java deleted file mode 100644 index 2253872d5..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/UserIdEditor.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.content.Context; -import android.text.Editable; -import android.text.TextWatcher; -import android.util.AttributeSet; -import android.util.Patterns; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.AutoCompleteTextView; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.RadioButton; -import com.beardedhen.androidbootstrap.BootstrapButton; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.helper.ContactHelper; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; - -import java.util.regex.Matcher; - -public class UserIdEditor extends LinearLayout implements Editor, OnClickListener { - private EditorListener mEditorListener = null; - - private BootstrapButton mDeleteButton; - private RadioButton mIsMainUserId; - private String mOriginalID; - private EditText mName; - private String mOriginalName; - private AutoCompleteTextView mEmail; - private String mOriginalEmail; - private EditText mComment; - private String mOriginalComment; - private boolean mOriginallyMainUserID; - private boolean mIsNewId; - - public void setCanBeEdited(boolean canBeEdited) { - if (!canBeEdited) { - mDeleteButton.setVisibility(View.INVISIBLE); - mName.setEnabled(false); - mIsMainUserId.setEnabled(false); - mEmail.setEnabled(false); - mComment.setEnabled(false); - } - } - - public static class InvalidEmailException extends Exception { - static final long serialVersionUID = 0xf812773345L; - - public InvalidEmailException(String message) { - super(message); - } - } - - public UserIdEditor(Context context) { - super(context); - } - - public UserIdEditor(Context context, AttributeSet attrs) { - super(context, attrs); - } - - TextWatcher mTextWatcher = new TextWatcher() { - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void afterTextChanged(Editable s) { - if (mEditorListener != null) { - mEditorListener.onEdited(); - } - } - }; - - @Override - protected void onFinishInflate() { - setDrawingCacheEnabled(true); - setAlwaysDrawnWithCacheEnabled(true); - - mDeleteButton = (BootstrapButton) findViewById(R.id.delete); - mDeleteButton.setOnClickListener(this); - mIsMainUserId = (RadioButton) findViewById(R.id.isMainUserId); - mIsMainUserId.setOnClickListener(this); - - mName = (EditText) findViewById(R.id.name); - mName.addTextChangedListener(mTextWatcher); - mEmail = (AutoCompleteTextView) findViewById(R.id.email); - mComment = (EditText) findViewById(R.id.comment); - mComment.addTextChangedListener(mTextWatcher); - - - mEmail.setThreshold(1); // Start working from first character - mEmail.setAdapter( - new ArrayAdapter<String> - (this.getContext(), android.R.layout.simple_dropdown_item_1line, - ContactHelper.getMailAccounts(getContext()) - )); - mEmail.addTextChangedListener(new TextWatcher(){ - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { } - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { } - - @Override - public void afterTextChanged(Editable editable) { - String email = editable.toString(); - if (email.length() > 0) { - Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(email); - if (emailMatcher.matches()) { - mEmail.setCompoundDrawablesWithIntrinsicBounds(0, 0, - android.R.drawable.presence_online, 0); - } else { - mEmail.setCompoundDrawablesWithIntrinsicBounds(0, 0, - android.R.drawable.presence_offline, 0); - } - } else { - // remove drawable if email is empty - mEmail.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); - } - if (mEditorListener != null) { - mEditorListener.onEdited(); - } - } - }); - - super.onFinishInflate(); - } - - public void setValue(String userId, boolean isMainID, boolean isNewId) { - - mName.setText(""); - mOriginalName = ""; - mComment.setText(""); - mOriginalComment = ""; - mEmail.setText(""); - mOriginalEmail = ""; - mIsNewId = isNewId; - mOriginalID = userId; - - String[] result = PgpKeyHelper.splitUserId(userId); - if (result[0] != null) { - mName.setText(result[0]); - mOriginalName = result[0]; - } - if (result[1] != null) { - mEmail.setText(result[1]); - mOriginalEmail = result[1]; - } - if (result[2] != null) { - mComment.setText(result[2]); - mOriginalComment = result[2]; - } - - mOriginallyMainUserID = isMainID; - setIsMainUserId(isMainID); - } - - public String getValue() { - String name = ("" + mName.getText()).trim(); - String email = ("" + mEmail.getText()).trim(); - String comment = ("" + mComment.getText()).trim(); - - String userId = name; - if (comment.length() > 0) { - userId += " (" + comment + ")"; - } - if (email.length() > 0) { - userId += " <" + email + ">"; - } - - if (userId.equals("")) { - // ok, empty one... - return userId; - } - //TODO: check gpg accepts an entirely empty ID packet. specs say this is allowed - return userId; - } - - public void onClick(View v) { - final ViewGroup parent = (ViewGroup) getParent(); - if (v == mDeleteButton) { - boolean wasMainUserId = mIsMainUserId.isChecked(); - parent.removeView(this); - if (mEditorListener != null) { - mEditorListener.onDeleted(this, mIsNewId); - } - if (wasMainUserId && parent.getChildCount() > 0) { - UserIdEditor editor = (UserIdEditor) parent.getChildAt(0); - editor.setIsMainUserId(true); - } - } else if (v == mIsMainUserId) { - for (int i = 0; i < parent.getChildCount(); ++i) { - UserIdEditor editor = (UserIdEditor) parent.getChildAt(i); - if (editor == this) { - editor.setIsMainUserId(true); - } else { - editor.setIsMainUserId(false); - } - } - if (mEditorListener != null) { - mEditorListener.onEdited(); - } - } - } - - public void setIsMainUserId(boolean value) { - mIsMainUserId.setChecked(value); - } - - public boolean isMainUserId() { - return mIsMainUserId.isChecked(); - } - - public void setEditorListener(EditorListener listener) { - mEditorListener = listener; - } - - @Override - public boolean needsSaving() { - boolean retval = false; //(mOriginallyMainUserID != isMainUserId()); - retval |= !(mOriginalName.equals(("" + mName.getText()).trim())); - retval |= !(mOriginalEmail.equals(("" + mEmail.getText()).trim())); - retval |= !(mOriginalComment.equals(("" + mComment.getText()).trim())); - retval |= mIsNewId; - return retval; - } - - public boolean getIsOriginallyMainUserID() { - return mOriginallyMainUserID; - } - - public boolean primarySwapped() { - return (mOriginallyMainUserID != isMainUserId()); - } - - public String getOriginalID() { - return mOriginalID; - } - - public boolean getIsNewID() { return mIsNewId; } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java deleted file mode 100644 index d2f4cc003..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.util; - -import android.annotation.SuppressLint; -import android.app.Activity; -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.openpgp.PGPEncryptedData; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; - -import java.util.HashMap; - -@SuppressLint("UseSparseArrays") -public class AlgorithmNames { - Activity mActivity; - - HashMap<Integer, String> mEncryptionNames = new HashMap<Integer, String>(); - HashMap<Integer, String> mHashNames = new HashMap<Integer, String>(); - HashMap<Integer, String> mCompressionNames = new HashMap<Integer, String>(); - - public AlgorithmNames(Activity context) { - super(); - this.mActivity = context; - - mEncryptionNames.put(PGPEncryptedData.AES_128, "AES-128"); - mEncryptionNames.put(PGPEncryptedData.AES_192, "AES-192"); - mEncryptionNames.put(PGPEncryptedData.AES_256, "AES-256"); - mEncryptionNames.put(PGPEncryptedData.BLOWFISH, "Blowfish"); - mEncryptionNames.put(PGPEncryptedData.TWOFISH, "Twofish"); - mEncryptionNames.put(PGPEncryptedData.CAST5, "CAST5"); - mEncryptionNames.put(PGPEncryptedData.DES, "DES"); - mEncryptionNames.put(PGPEncryptedData.TRIPLE_DES, "Triple DES"); - mEncryptionNames.put(PGPEncryptedData.IDEA, "IDEA"); - - mHashNames.put(HashAlgorithmTags.MD5, "MD5"); - mHashNames.put(HashAlgorithmTags.RIPEMD160, "RIPEMD-160"); - mHashNames.put(HashAlgorithmTags.SHA1, "SHA-1"); - mHashNames.put(HashAlgorithmTags.SHA224, "SHA-224"); - mHashNames.put(HashAlgorithmTags.SHA256, "SHA-256"); - mHashNames.put(HashAlgorithmTags.SHA384, "SHA-384"); - mHashNames.put(HashAlgorithmTags.SHA512, "SHA-512"); - - mCompressionNames.put(Id.choice.compression.none, mActivity.getString(R.string.choice_none) - + " (" + mActivity.getString(R.string.compression_fast) + ")"); - mCompressionNames.put(Id.choice.compression.zip, - "ZIP (" + mActivity.getString(R.string.compression_fast) + ")"); - mCompressionNames.put(Id.choice.compression.zlib, - "ZLIB (" + mActivity.getString(R.string.compression_fast) + ")"); - mCompressionNames.put(Id.choice.compression.bzip2, - "BZIP2 (" + mActivity.getString(R.string.compression_very_slow) + ")"); - } - - public HashMap<Integer, String> getEncryptionNames() { - return mEncryptionNames; - } - - public void setEncryptionNames(HashMap<Integer, String> encryptionNames) { - this.mEncryptionNames = encryptionNames; - } - - public HashMap<Integer, String> getHashNames() { - return mHashNames; - } - - public void setHashNames(HashMap<Integer, String> hashNames) { - this.mHashNames = hashNames; - } - - public HashMap<Integer, String> getCompressionNames() { - return mCompressionNames; - } - - public void setCompressionNames(HashMap<Integer, String> compressionNames) { - this.mCompressionNames = compressionNames; - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java deleted file mode 100644 index 1a6184d9c..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Choice.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.util; - -public class Choice { - private String mName; - private int mId; - - public Choice() { - mId = -1; - mName = ""; - } - - public Choice(int id, String name) { - mId = id; - mName = name; - } - - public int getId() { - return mId; - } - - public String getName() { - return mName; - } - - @Override - public String toString() { - return mName; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java deleted file mode 100644 index 5efc732e4..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2011 Thialfihar <thi@thialfihar.org> - * Copyright (C) 2011 Senecaso - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.util; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class HkpKeyServer extends KeyServer { - private static class HttpError extends Exception { - private static final long serialVersionUID = 1718783705229428893L; - private int mCode; - private String mData; - - public HttpError(int code, String data) { - super("" + code + ": " + data); - mCode = code; - mData = data; - } - - public int getCode() { - return mCode; - } - - public String getData() { - return mData; - } - } - - private String mHost; - private short mPort; - - /** - * pub:%keyid%:%algo%:%keylen%:%creationdate%:%expirationdate%:%flags% - * <ul> - * <li>%<b>keyid</b>% = this is either the fingerprint or the key ID of the key. - * Either the 16-digit or 8-digit key IDs are acceptable, but obviously the fingerprint is best. - * </li> - * <li>%<b>algo</b>% = the algorithm number, (i.e. 1==RSA, 17==DSA, etc). - * See <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a></li> - * <li>%<b>keylen</b>% = the key length (i.e. 1024, 2048, 4096, etc.)</li> - * <li>%<b>creationdate</b>% = creation date of the key in standard - * <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of - * seconds since 1/1/1970 UTC time)</li> - * <li>%<b>expirationdate</b>% = expiration date of the key in standard - * <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of - * seconds since 1/1/1970 UTC time)</li> - * <li>%<b>flags</b>% = letter codes to indicate details of the key, if any. Flags may be in any - * order. The meaning of "disabled" is implementation-specific. Note that individual flags may - * be unimplemented, so the absence of a given flag does not necessarily mean the absence of the - * detail. - * <ul> - * <li>r == revoked</li> - * <li>d == disabled</li> - * <li>e == expired</li> - * </ul> - * </li> - * </ul> - * - * @see <a href="http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5.2"> - * 5.2. Machine Readable Indexes</a> - * in Internet-Draft OpenPGP HTTP Keyserver Protocol Document - */ - public static final Pattern PUB_KEY_LINE = Pattern - .compile("pub:([0-9a-fA-F]+):([0-9]+):([0-9]+):([0-9]+):([0-9]*):([rde]*)[ \n\r]*" // pub line - + "(uid:(.*):([0-9]+):([0-9]*):([rde]*))+", // one or more uid lines - Pattern.CASE_INSENSITIVE); - - /** - * uid:%escaped uid string%:%creationdate%:%expirationdate%:%flags% - * <ul> - * <li>%<b>escaped uid string</b>% = the user ID string, with HTTP %-escaping for anything that - * isn't 7-bit safe as well as for the ":" character. Any other characters may be escaped, as - * desired.</li> - * <li>%<b>creationdate</b>% = creation date of the key in standard - * <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of - * seconds since 1/1/1970 UTC time)</li> - * <li>%<b>expirationdate</b>% = expiration date of the key in standard - * <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of - * seconds since 1/1/1970 UTC time)</li> - * <li>%<b>flags</b>% = letter codes to indicate details of the key, if any. Flags may be in any - * order. The meaning of "disabled" is implementation-specific. Note that individual flags may - * be unimplemented, so the absence of a given flag does not necessarily mean the absence of - * the detail. - * <ul> - * <li>r == revoked</li> - * <li>d == disabled</li> - * <li>e == expired</li> - * </ul> - * </li> - * </ul> - */ - public static final Pattern UID_LINE = Pattern - .compile("uid:(.*):([0-9]+):([0-9]*):([rde]*)", - Pattern.CASE_INSENSITIVE); - - private static final short PORT_DEFAULT = 11371; - - /** - * @param hostAndPort may be just - * "<code>hostname</code>" (eg. "<code>pool.sks-keyservers.net</code>"), then it will - * connect using {@link #PORT_DEFAULT}. However, port may be specified after colon - * ("<code>hostname:port</code>", eg. "<code>p80.pool.sks-keyservers.net:80</code>"). - */ - public HkpKeyServer(String hostAndPort) { - String host = hostAndPort; - short port = PORT_DEFAULT; - final int colonPosition = hostAndPort.lastIndexOf(':'); - if (colonPosition > 0) { - host = hostAndPort.substring(0, colonPosition); - final String portStr = hostAndPort.substring(colonPosition + 1); - port = Short.decode(portStr); - } - mHost = host; - mPort = port; - } - - public HkpKeyServer(String host, short port) { - mHost = host; - mPort = port; - } - - private static String readAll(InputStream in, String encoding) throws IOException { - ByteArrayOutputStream raw = new ByteArrayOutputStream(); - - byte buffer[] = new byte[1 << 16]; - int n = 0; - while ((n = in.read(buffer)) != -1) { - raw.write(buffer, 0, n); - } - - if (encoding == null) { - encoding = "utf8"; - } - return raw.toString(encoding); - } - - private String query(String request) throws QueryException, HttpError { - InetAddress ips[]; - try { - ips = InetAddress.getAllByName(mHost); - } catch (UnknownHostException e) { - throw new QueryException(e.toString()); - } - for (int i = 0; i < ips.length; ++i) { - try { - String url = "http://" + ips[i].getHostAddress() + ":" + mPort + request; - Log.d(Constants.TAG, "hkp keyserver query: " + url); - URL realUrl = new URL(url); - HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); - conn.setConnectTimeout(5000); - conn.setReadTimeout(25000); - conn.connect(); - int response = conn.getResponseCode(); - if (response >= 200 && response < 300) { - return readAll(conn.getInputStream(), conn.getContentEncoding()); - } else { - String data = readAll(conn.getErrorStream(), conn.getContentEncoding()); - throw new HttpError(response, data); - } - } catch (MalformedURLException e) { - // nothing to do, try next IP - } catch (IOException e) { - // nothing to do, try next IP - } - } - - throw new QueryException("querying server(s) for '" + mHost + "' failed"); - } - - @Override - public ArrayList<ImportKeysListEntry> search(String query) throws QueryException, TooManyResponses, - InsufficientQuery { - ArrayList<ImportKeysListEntry> results = new ArrayList<ImportKeysListEntry>(); - - if (query.length() < 3) { - throw new InsufficientQuery(); - } - - String encodedQuery; - try { - encodedQuery = URLEncoder.encode(query, "utf8"); - } catch (UnsupportedEncodingException e) { - return null; - } - String request = "/pks/lookup?op=index&options=mr&search=" + encodedQuery; - - String data; - try { - data = query(request); - } catch (HttpError e) { - if (e.getCode() == 404) { - return results; - } else { - if (e.getData().toLowerCase(Locale.US).contains("no keys found")) { - return results; - } else if (e.getData().toLowerCase(Locale.US).contains("too many")) { - throw new TooManyResponses(); - } else if (e.getData().toLowerCase(Locale.US).contains("insufficient")) { - throw new InsufficientQuery(); - } - } - throw new QueryException("querying server(s) for '" + mHost + "' failed"); - } - - final Matcher matcher = PUB_KEY_LINE.matcher(data); - while (matcher.find()) { - final ImportKeysListEntry entry = new ImportKeysListEntry(); - - entry.setBitStrength(Integer.parseInt(matcher.group(3))); - - final int algorithmId = Integer.decode(matcher.group(2)); - entry.setAlgorithm(ImportKeysListEntry.getAlgorithmFromId(algorithmId)); - - // group 1 contains the full fingerprint (v4) or the long key id if available - // see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr - String fingerprintOrKeyId = matcher.group(1); - if (fingerprintOrKeyId.length() > 16) { - entry.setFingerPrintHex(fingerprintOrKeyId.toLowerCase(Locale.US)); - entry.setKeyIdHex("0x" + fingerprintOrKeyId.substring(fingerprintOrKeyId.length() - - 16, fingerprintOrKeyId.length())); - } else { - // set key id only - entry.setKeyIdHex("0x" + fingerprintOrKeyId); - } - - final long creationDate = Long.parseLong(matcher.group(4)); - final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - tmpGreg.setTimeInMillis(creationDate * 1000); - entry.setDate(tmpGreg.getTime()); - - entry.setRevoked(matcher.group(6).contains("r")); - - ArrayList<String> userIds = new ArrayList<String>(); - final String uidLines = matcher.group(7); - final Matcher uidMatcher = UID_LINE.matcher(uidLines); - while (uidMatcher.find()) { - String tmp = uidMatcher.group(1).trim(); - if (tmp.contains("%")) { - try { - // converts Strings like "Universit%C3%A4t" to a proper encoding form "Universität". - tmp = (URLDecoder.decode(tmp, "UTF8")); - } catch (UnsupportedEncodingException ignored) { - // will never happen, because "UTF8" is supported - } - } - userIds.add(tmp); - } - entry.setUserIds(userIds); - - results.add(entry); - } - return results; - } - - @Override - public String get(String keyIdHex) throws QueryException { - HttpClient client = new DefaultHttpClient(); - try { - String query = "http://" + mHost + ":" + mPort + - "/pks/lookup?op=get&options=mr&search=" + keyIdHex; - Log.d(Constants.TAG, "hkp keyserver get: " + query); - HttpGet get = new HttpGet(query); - HttpResponse response = client.execute(get); - if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - throw new QueryException("not found"); - } - - HttpEntity entity = response.getEntity(); - InputStream is = entity.getContent(); - String data = readAll(is, EntityUtils.getContentCharSet(entity)); - Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(data); - if (matcher.find()) { - return matcher.group(1); - } - } catch (IOException e) { - // nothing to do, better luck on the next keyserver - } finally { - client.getConnectionManager().shutdown(); - } - - return null; - } - - @Override - public void add(String armoredKey) throws AddKeyException { - HttpClient client = new DefaultHttpClient(); - try { - String query = "http://" + mHost + ":" + mPort + "/pks/add"; - HttpPost post = new HttpPost(query); - Log.d(Constants.TAG, "hkp keyserver add: " + query); - List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); - nameValuePairs.add(new BasicNameValuePair("keytext", armoredKey)); - post.setEntity(new UrlEncodedFormEntity(nameValuePairs)); - - HttpResponse response = client.execute(post); - if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - throw new AddKeyException(); - } - } catch (IOException e) { - // nothing to do, better luck on the next keyserver - } finally { - client.getConnectionManager().shutdown(); - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/InputData.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/InputData.java deleted file mode 100644 index 28cfa11f2..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/InputData.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.util; - -import java.io.InputStream; - -public class InputData { - private PositionAwareInputStream mInputStream; - private long mSize; - - public InputData(InputStream inputStream, long size) { - mInputStream = new PositionAwareInputStream(inputStream); - mSize = size; - } - - public InputStream getInputStream() { - return mInputStream; - } - - public long getSize() { - return mSize; - } - - public long getStreamPosition() { - return mInputStream.position(); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java deleted file mode 100644 index ae87deb31..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IntentIntegratorSupportV4.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2012 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.util; - -import com.google.zxing.integration.android.IntentIntegrator; - -import android.content.Intent; -import android.support.v4.app.Fragment; - -/** - * IntentIntegrator for the V4 Android compatibility package. - * - * @author Lachezar Dobrev - */ -public final class IntentIntegratorSupportV4 extends IntentIntegrator { - - private final Fragment mFragment; - - /** - * @param fragment Fragment to handle activity response. - */ - public IntentIntegratorSupportV4(Fragment fragment) { - super(fragment.getActivity()); - this.mFragment = fragment; - } - - @Override - protected void startActivityForResult(Intent intent, int code) { - mFragment.startActivityForResult(intent, code); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java deleted file mode 100644 index 3af674526..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/IterableIterator.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.util; - -import java.util.ArrayList; -import java.util.Iterator; - -public class IterableIterator<T> implements Iterable<T> { - private Iterator<T> mIter; - - public IterableIterator(Iterator<T> iter, boolean failsafe) { - mIter = iter; - if (failsafe && mIter == null) { - // is there a better way? - mIter = new ArrayList<T>().iterator(); - } - } - public IterableIterator(Iterator<T> iter) { - this(iter, false); - } - - public Iterator<T> iterator() { - return mIter; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java deleted file mode 100644 index 7f70867a5..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2011 Thialfihar <thi@thialfihar.org> - * Copyright (C) 2011 Senecaso - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.util; - -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; - -import java.util.List; - -public abstract class KeyServer { - public static class QueryException extends Exception { - private static final long serialVersionUID = 2703768928624654512L; - - public QueryException(String message) { - super(message); - } - } - - public static class TooManyResponses extends Exception { - private static final long serialVersionUID = 2703768928624654513L; - } - - public static class InsufficientQuery extends Exception { - private static final long serialVersionUID = 2703768928624654514L; - } - - public static class AddKeyException extends Exception { - private static final long serialVersionUID = -507574859137295530L; - } - - abstract List<ImportKeysListEntry> search(String query) throws QueryException, TooManyResponses, - InsufficientQuery; - - abstract String get(String keyIdHex) throws QueryException; - - abstract void add(String armoredKey) throws AddKeyException; -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java deleted file mode 100644 index b205bd556..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.util; - -public interface KeychainServiceListener { - boolean hasServiceStopped(); -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java deleted file mode 100644 index f58f1757a..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.util; - -import org.sufficientlysecure.keychain.Constants; - -/** - * Wraps Android Logging to enable or disable debug output using Constants - */ -public final class Log { - - public static void v(String tag, String msg) { - if (Constants.DEBUG) { - android.util.Log.v(tag, msg); - } - } - - public static void v(String tag, String msg, Throwable tr) { - if (Constants.DEBUG) { - android.util.Log.v(tag, msg, tr); - } - } - - public static void d(String tag, String msg) { - if (Constants.DEBUG) { - android.util.Log.d(tag, msg); - } - } - - public static void d(String tag, String msg, Throwable tr) { - if (Constants.DEBUG) { - android.util.Log.d(tag, msg, tr); - } - } - - public static void i(String tag, String msg) { - if (Constants.DEBUG) { - android.util.Log.i(tag, msg); - } - } - - public static void i(String tag, String msg, Throwable tr) { - if (Constants.DEBUG) { - android.util.Log.i(tag, msg, tr); - } - } - - public static void w(String tag, String msg) { - android.util.Log.w(tag, msg); - } - - public static void w(String tag, String msg, Throwable tr) { - android.util.Log.w(tag, msg, tr); - } - - public static void w(String tag, Throwable tr) { - android.util.Log.w(tag, tr); - } - - public static void e(String tag, String msg) { - android.util.Log.e(tag, msg); - } - - public static void e(String tag, String msg, Throwable tr) { - android.util.Log.e(tag, msg, tr); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PRNGFixes.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PRNGFixes.java deleted file mode 100644 index 2d8fbcd81..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PRNGFixes.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * This software is provided 'as-is', without any express or implied - * warranty. In no event will Google be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, as long as the origin is not misrepresented. - */ - -package org.sufficientlysecure.keychain.util; - -import android.os.Build; -import android.os.Process; -import android.util.Log; - -import java.io.*; -import java.security.*; - -/** - * Fixes for the output of the default PRNG having low entropy. - * <p/> - * The fixes need to be applied via {@link #apply()} before any use of Java Cryptography - * Architecture primitives. A good place to invoke them is in the application's {@code onCreate}. - * <p/> - * copied from http://android-developers.blogspot.de/2013/08/some-securerandom-thoughts.html - * <p/> - * <p/> - * More information on these Android bugs: - * http://blog.k3170makan.com/2013/08/more-details-on-android-jca-prng-flaw.html - * Paper: "Randomly failed! Weaknesses in Java Pseudo Random Number Generators (PRNGs)" - * <p/> - * <p/> - * Sep 15, 2013: - * On some devices /dev/urandom is non-writable! - * No need to seed /dev/urandom. urandom should have enough seeds from the OS and kernel. - * Only OpenSSL seeds are broken. See http://emboss.github.io/blog/2013/08/21/openssl-prng-is-not-really-fork-safe - * <p/> - * see also: - * https://github.com/k9mail/k-9/commit/dda8f64276d4d29c43f86237cd77819c28f22f21 - * In addition to a couple of custom ROMs linking /dev/urandom to a non-writable - * random version, now Samsung's SELinux policy also prevents apps from opening - * /dev/urandom for writing. Since we shouldn't need to write to /dev/urandom anyway - * we now simply don't. - * <p/> - * <p/> - * Sep 17, 2013: - * Updated from official blogpost: - * Update: the original code sample below crashed on a small fraction of Android - * devices due to /dev/urandom not being writable. We have now updated the code sample to handle this case gracefully. - */ -public final class PRNGFixes { - - private static final int VERSION_CODE_JELLY_BEAN = 16; - private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18; - private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL = - getBuildFingerprintAndDeviceSerial(); - - /** - * Hidden constructor to prevent instantiation. - */ - private PRNGFixes() { - } - - /** - * Applies all fixes. - * - * @throws SecurityException if a fix is needed but could not be applied. - */ - public static void apply() { - applyOpenSSLFix(); - installLinuxPRNGSecureRandom(); - } - - /** - * Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the - * fix is not needed. - * - * @throws SecurityException if the fix is needed but could not be applied. - */ - private static void applyOpenSSLFix() throws SecurityException { - if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN) - || (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) { - // No need to apply the fix - return; - } - - try { - // Mix in the device- and invocation-specific seed. - Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto") - .getMethod("RAND_seed", byte[].class) - .invoke(null, generateSeed()); - - // Mix output of Linux PRNG into OpenSSL's PRNG - int bytesRead = (Integer) Class.forName( - "org.apache.harmony.xnet.provider.jsse.NativeCrypto") - .getMethod("RAND_load_file", String.class, long.class) - .invoke(null, "/dev/urandom", 1024); - if (bytesRead != 1024) { - throw new IOException( - "Unexpected number of bytes read from Linux PRNG: " - + bytesRead); - } - } catch (Exception e) { - throw new SecurityException("Failed to seed OpenSSL PRNG", e); - } - } - - /** - * Installs a Linux PRNG-backed {@code SecureRandom} implementation as the - * default. Does nothing if the implementation is already the default or if - * there is not need to install the implementation. - * - * @throws SecurityException if the fix is needed but could not be applied. - */ - private static void installLinuxPRNGSecureRandom() - throws SecurityException { - if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) { - // No need to apply the fix - return; - } - - // Install a Linux PRNG-based SecureRandom implementation as the - // default, if not yet installed. - Provider[] secureRandomProviders = - Security.getProviders("SecureRandom.SHA1PRNG"); - if ((secureRandomProviders == null) - || (secureRandomProviders.length < 1) - || (!LinuxPRNGSecureRandomProvider.class.equals( - secureRandomProviders[0].getClass()))) { - Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1); - } - - // Assert that new SecureRandom() and - // SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed - // by the Linux PRNG-based SecureRandom implementation. - SecureRandom rng1 = new SecureRandom(); - if (!LinuxPRNGSecureRandomProvider.class.equals( - rng1.getProvider().getClass())) { - throw new SecurityException( - "new SecureRandom() backed by wrong Provider: " - + rng1.getProvider().getClass()); - } - - SecureRandom rng2; - try { - rng2 = SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - throw new SecurityException("SHA1PRNG not available", e); - } - if (!LinuxPRNGSecureRandomProvider.class.equals( - rng2.getProvider().getClass())) { - throw new SecurityException( - "SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong" - + " Provider: " + rng2.getProvider().getClass()); - } - } - - /** - * {@code Provider} of {@code SecureRandom} engines which pass through - * all requests to the Linux PRNG. - */ - private static class LinuxPRNGSecureRandomProvider extends Provider { - - public LinuxPRNGSecureRandomProvider() { - super("LinuxPRNG", - 1.0, - "A Linux-specific random number provider that uses" - + " /dev/urandom"); - // Although /dev/urandom is not a SHA-1 PRNG, some apps - // explicitly request a SHA1PRNG SecureRandom and we thus need to - // prevent them from getting the default implementation whose output - // may have low entropy. - put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName()); - put("SecureRandom.SHA1PRNG ImplementedIn", "Software"); - } - } - - /** - * {@link SecureRandomSpi} which passes all requests to the Linux PRNG - * ({@code /dev/urandom}). - */ - public static class LinuxPRNGSecureRandom extends SecureRandomSpi { - - /* - * IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed - * are passed through to the Linux PRNG (/dev/urandom). Instances of - * this class seed themselves by mixing in the current time, PID, UID, - * build fingerprint, and hardware serial number (where available) into - * Linux PRNG. - * - * Concurrency: Read requests to the underlying Linux PRNG are - * serialized (on sLock) to ensure that multiple threads do not get - * duplicated PRNG output. - */ - - private static final File URANDOM_FILE = new File("/dev/urandom"); - - private static final Object sLock = new Object(); - - /** - * Input stream for reading from Linux PRNG or {@code null} if not yet - * opened. - * - * @GuardedBy("sLock") - */ - private static DataInputStream sUrandomIn; - - /** - * Output stream for writing to Linux PRNG or {@code null} if not yet - * opened. - * - * @GuardedBy("sLock") - */ - private static OutputStream sUrandomOut; - - /** - * Whether this engine instance has been seeded. This is needed because - * each instance needs to seed itself if the client does not explicitly - * seed it. - */ - private boolean mSeeded; - - @Override - protected void engineSetSeed(byte[] bytes) { - try { - OutputStream out; - synchronized (sLock) { - out = getUrandomOutputStream(); - } - out.write(bytes); - out.flush(); - } catch (IOException e) { - // On a small fraction of devices /dev/urandom is not writable. - // Log and ignore. - Log.w(PRNGFixes.class.getSimpleName(), - "Failed to mix seed into " + URANDOM_FILE); - } finally { - mSeeded = true; - } - } - - @Override - protected void engineNextBytes(byte[] bytes) { - if (!mSeeded) { - // Mix in the device- and invocation-specific seed. - engineSetSeed(generateSeed()); - } - - try { - DataInputStream in; - synchronized (sLock) { - in = getUrandomInputStream(); - } - synchronized (in) { - in.readFully(bytes); - } - } catch (IOException e) { - throw new SecurityException( - "Failed to read from " + URANDOM_FILE, e); - } - } - - @Override - protected byte[] engineGenerateSeed(int size) { - byte[] seed = new byte[size]; - engineNextBytes(seed); - return seed; - } - - private DataInputStream getUrandomInputStream() { - synchronized (sLock) { - if (sUrandomIn == null) { - // NOTE: Consider inserting a BufferedInputStream between - // DataInputStream and FileInputStream if you need higher - // PRNG output performance and can live with future PRNG - // output being pulled into this process prematurely. - try { - sUrandomIn = new DataInputStream( - new FileInputStream(URANDOM_FILE)); - } catch (IOException e) { - throw new SecurityException("Failed to open " - + URANDOM_FILE + " for reading", e); - } - } - return sUrandomIn; - } - } - - private OutputStream getUrandomOutputStream() throws IOException { - synchronized (sLock) { - if (sUrandomOut == null) { - sUrandomOut = new FileOutputStream(URANDOM_FILE); - } - return sUrandomOut; - } - } - } - - /** - * Generates a device- and invocation-specific seed to be mixed into the - * Linux PRNG. - */ - private static byte[] generateSeed() { - try { - ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream(); - DataOutputStream seedBufferOut = - new DataOutputStream(seedBuffer); - seedBufferOut.writeLong(System.currentTimeMillis()); - seedBufferOut.writeLong(System.nanoTime()); - seedBufferOut.writeInt(Process.myPid()); - seedBufferOut.writeInt(Process.myUid()); - seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL); - seedBufferOut.close(); - return seedBuffer.toByteArray(); - } catch (IOException e) { - throw new SecurityException("Failed to generate seed", e); - } - } - - /** - * Gets the hardware serial number of this device. - * - * @return serial number or {@code null} if not available. - */ - private static String getDeviceSerialNumber() { - // We're using the Reflection API because Build.SERIAL is only available - // since API Level 9 (Gingerbread, Android 2.3). - try { - return (String) Build.class.getField("SERIAL").get(null); - } catch (Exception ignored) { - return null; - } - } - - private static byte[] getBuildFingerprintAndDeviceSerial() { - StringBuilder result = new StringBuilder(); - String fingerprint = Build.FINGERPRINT; - if (fingerprint != null) { - result.append(fingerprint); - } - String serial = getDeviceSerialNumber(); - if (serial != null) { - result.append(serial); - } - try { - return result.toString().getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("UTF-8 encoding not supported"); - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PausableThreadPoolExecutor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PausableThreadPoolExecutor.java deleted file mode 100644 index 5ec915810..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PausableThreadPoolExecutor.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.util; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.RejectedExecutionHandler; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -/** - * Example from - * http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html - */ -public class PausableThreadPoolExecutor extends ThreadPoolExecutor { - - public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, - TimeUnit unit, BlockingQueue<Runnable> workQueue, - RejectedExecutionHandler handler) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); - } - - public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, - TimeUnit unit, BlockingQueue<Runnable> workQueue, - ThreadFactory threadFactory, - RejectedExecutionHandler handler) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); - } - - public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, - TimeUnit unit, BlockingQueue<Runnable> workQueue, - ThreadFactory threadFactory) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); - } - - public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, - TimeUnit unit, BlockingQueue<Runnable> workQueue) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); - } - - private boolean mIsPaused; - private ReentrantLock mPauseLock = new ReentrantLock(); - private Condition mUnPaused = mPauseLock.newCondition(); - - protected void beforeExecute(Thread t, Runnable r) { - super.beforeExecute(t, r); - mPauseLock.lock(); - try { - while (mIsPaused) { - mUnPaused.await(); - } - } catch (InterruptedException ie) { - t.interrupt(); - } finally { - mPauseLock.unlock(); - } - } - - public void pause() { - mPauseLock.lock(); - try { - mIsPaused = true; - } finally { - mPauseLock.unlock(); - } - } - - public void resume() { - mPauseLock.lock(); - try { - mIsPaused = false; - mUnPaused.signalAll(); - } finally { - mPauseLock.unlock(); - } - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PositionAwareInputStream.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PositionAwareInputStream.java deleted file mode 100644 index 4fcd3047f..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/PositionAwareInputStream.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.util; - -import java.io.IOException; -import java.io.InputStream; - -public class PositionAwareInputStream extends InputStream { - private InputStream mStream; - private long mPosition; - - public PositionAwareInputStream(InputStream in) { - mStream = in; - mPosition = 0; - } - - @Override - public int read() throws IOException { - int ch = mStream.read(); - ++mPosition; - return ch; - } - - @Override - public int available() throws IOException { - return mStream.available(); - } - - @Override - public void close() throws IOException { - mStream.close(); - } - - @Override - public boolean markSupported() { - return false; - } - - @Override - public int read(byte[] b) throws IOException { - int result = mStream.read(b); - mPosition += result; - return result; - } - - @Override - public int read(byte[] b, int offset, int length) throws IOException { - int result = mStream.read(b, offset, length); - mPosition += result; - return result; - } - - @Override - public synchronized void reset() throws IOException { - mStream.reset(); - mPosition = 0; - } - - @Override - public long skip(long n) throws IOException { - long result = mStream.skip(n); - mPosition += result; - return result; - } - - public long position() { - return mPosition; - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Primes.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Primes.java deleted file mode 100644 index 28a12bf37..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/Primes.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.util; - -import java.math.BigInteger; - -/** - * Primes for ElGamal - */ -public final class Primes { - // taken from http://www.ietf.org/rfc/rfc3526.txt - public static final String P1536 = - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + - "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + - "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + - "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF"; - - public static final String P2048 = - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + - "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + - "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + - "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" + - "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" + - "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" + - "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"; - - public static final String P3072 = - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + - "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + - "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + - "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" + - "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" + - "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" + - "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" + - "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" + - "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" + - "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" + - "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" + - "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF"; - - public static final String P4096 = - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + - "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + - "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + - "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" + - "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" + - "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" + - "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" + - "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" + - "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" + - "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" + - "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" + - "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" + - "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" + - "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" + - "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" + - "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" + - "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" + - "FFFFFFFF FFFFFFFF"; - - public static final String P6144 = - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + - "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + - "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + - "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" + - "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" + - "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" + - "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" + - "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" + - "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" + - "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" + - "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" + - "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" + - "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" + - "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" + - "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" + - "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" + - "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" + - "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" + - "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" + - "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" + - "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" + - "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" + - "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" + - "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" + - "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" + - "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" + - "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" + - "12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF"; - - public static final String P8192 = - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + - "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + - "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + - "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" + - "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" + - "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" + - "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" + - "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" + - "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" + - "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" + - "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" + - "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" + - "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" + - "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" + - "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" + - "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" + - "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" + - "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" + - "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" + - "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" + - "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" + - "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" + - "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" + - "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" + - "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" + - "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" + - "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" + - "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" + - "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" + - "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" + - "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" + - "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" + - "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" + - "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" + - "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" + - "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" + - "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" + - "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" + - "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF"; - - public static BigInteger getBestPrime(int keySize) { - String primeString; - if (keySize >= (8192 + 6144) / 2) { - primeString = P8192; - } else if (keySize >= (6144 + 4096) / 2) { - primeString = P6144; - } else if (keySize >= (4096 + 3072) / 2) { - primeString = P4096; - } else if (keySize >= (3072 + 2048) / 2) { - primeString = P3072; - } else if (keySize >= (2048 + 1536) / 2) { - primeString = P2048; - } else { - primeString = P1536; - } - - return new BigInteger(primeString.replaceAll(" ", ""), 16); - } -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressDialogUpdater.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressDialogUpdater.java deleted file mode 100644 index 26c05ad0a..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressDialogUpdater.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2010 Thialfihar <thi@thialfihar.org> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.util; - -public interface ProgressDialogUpdater { - void setProgress(String message, int current, int total); - - void setProgress(int resourceId, int current, int total); - - void setProgress(int current, int total); -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java deleted file mode 100644 index 23961c05f..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/ProgressScaler.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.util; - -/** This is a simple class that wraps a ProgressDialogUpdater, scaling the progress - * values into a specified range. - */ -public class ProgressScaler implements ProgressDialogUpdater { - - final ProgressDialogUpdater mWrapped; - final int mFrom, mTo, mMax; - - public ProgressScaler(ProgressDialogUpdater wrapped, int from, int to, int max) { - this.mWrapped = wrapped; - this.mFrom = from; - this.mTo = to; - this.mMax = max; - } - - /** - * Set progressDialogUpdater of ProgressDialog by sending message to handler on UI thread - */ - public void setProgress(String message, int progress, int max) { - mWrapped.setProgress(message, mFrom + progress * (mTo - mFrom) / max, mMax); - } - - public void setProgress(int resourceId, int progress, int max) { - mWrapped.setProgress(resourceId, progress, mMax); - } - - public void setProgress(int progress, int max) { - mWrapped.setProgress(progress, max); - } - -} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java deleted file mode 100644 index af9034aa7..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/QrCodeUtils.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> - * Copyright (C) 2011 Andreas Schildbach - * - * 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 <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.util; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.EncodeHintType; -import com.google.zxing.WriterException; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.qrcode.QRCodeWriter; -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; - -import android.graphics.Bitmap; -import android.graphics.Color; - -import org.sufficientlysecure.keychain.Constants; - -import java.util.Hashtable; - -public class QrCodeUtils { - public static final QRCodeWriter QR_CODE_WRITER = new QRCodeWriter(); - - /** - * Generate Bitmap with QR Code based on input. - * - * @param input - * @param size - * @return QR Code as Bitmap - */ - public static Bitmap getQRCodeBitmap(final String input, final int size) { - try { - final Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); - hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); - final BitMatrix result = QR_CODE_WRITER.encode(input, BarcodeFormat.QR_CODE, size, - size, hints); - - final int width = result.getWidth(); - final int height = result.getHeight(); - final int[] pixels = new int[width * height]; - - for (int y = 0; y < height; y++) { - final int offset = y * width; - for (int x = 0; x < width; x++) { - pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.TRANSPARENT; - } - } - - final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - bitmap.setPixels(pixels, 0, width, 0, 0, width, height); - return bitmap; - } catch (final WriterException e) { - Log.e(Constants.TAG, "QrCodeUtils", e); - return null; - } - } - -} |