Merge branch 'master' into certs

Conflicts:
	OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
	OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
	OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
	OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
	OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyCertsFragment.java
	OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
This commit is contained in:
Vincent Breitmoser 2014-03-14 23:46:06 +01:00
commit a73e91c49c
127 changed files with 2469 additions and 2447 deletions

5
.gitignore vendored
View File

@ -31,3 +31,8 @@ pom.xml.*
#OS Specific #OS Specific
[Tt]humbs.db [Tt]humbs.db
#Lint output
OpenPGP-Keychain/lint-report.html
OpenPGP-Keychain/lint-report_files/*

View File

@ -3,7 +3,7 @@ jdk: oraclejdk7
before_install: before_install:
# Install base Android SDK # Install base Android SDK
- sudo apt-get update -qq - sudo apt-get update -qq
- if [ `uname -m` = x86_64 ]; then sudo apt-get install -qq --force-yes libgd2-xpm ia32-libs; fi - if [ `uname -m` = x86_64 ]; then sudo apt-get install -qq --force-yes libgd2-xpm lib32z1 lib32stdc++6; fi
- wget http://dl.google.com/android/android-sdk_r22.3-linux.tgz - wget http://dl.google.com/android/android-sdk_r22.3-linux.tgz
- tar xzf android-sdk_r22.3-linux.tgz - tar xzf android-sdk_r22.3-linux.tgz
- export ANDROID_HOME=$PWD/android-sdk-linux - export ANDROID_HOME=$PWD/android-sdk-linux

View File

@ -57,5 +57,7 @@ android {
// Do not abort build if lint finds errors // Do not abort build if lint finds errors
lintOptions { lintOptions {
abortOnError false abortOnError false
htmlReport true
htmlOutput file("lint-report.html")
} }
} }

View File

@ -16,10 +16,10 @@
package org.sufficientlysecure.keychain; package org.sufficientlysecure.keychain;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import android.os.Environment; import android.os.Environment;
import org.spongycastle.jce.provider.BouncyCastleProvider;
public final class Constants { public final class Constants {
public static final boolean DEBUG = BuildConfig.DEBUG; public static final boolean DEBUG = BuildConfig.DEBUG;
@ -40,14 +40,14 @@ public final class Constants {
public static final String INTENT_PREFIX = PACKAGE_NAME + ".action."; public static final String INTENT_PREFIX = PACKAGE_NAME + ".action.";
public static final class path { public static final class Path {
public static final String APP_DIR = Environment.getExternalStorageDirectory() public static final String APP_DIR = Environment.getExternalStorageDirectory()
+ "/OpenPGP-Keychain"; + "/OpenPGP-Keychain";
public static final String APP_DIR_FILE_SEC = APP_DIR + "/secexport.asc"; public static final String APP_DIR_FILE_SEC = APP_DIR + "/secexport.asc";
public static final String APP_DIR_FILE_PUB = APP_DIR + "/pubexport.asc"; public static final String APP_DIR_FILE_PUB = APP_DIR + "/pubexport.asc";
} }
public static final class pref { public static final class Pref {
public static final String DEFAULT_ENCRYPTION_ALGORITHM = "defaultEncryptionAlgorithm"; public static final String DEFAULT_ENCRYPTION_ALGORITHM = "defaultEncryptionAlgorithm";
public static final String DEFAULT_HASH_ALGORITHM = "defaultHashAlgorithm"; public static final String DEFAULT_HASH_ALGORITHM = "defaultHashAlgorithm";
public static final String DEFAULT_ASCII_ARMOUR = "defaultAsciiArmour"; public static final String DEFAULT_ASCII_ARMOUR = "defaultAsciiArmour";
@ -59,7 +59,7 @@ public final class Constants {
public static final String KEY_SERVERS = "keyServers"; public static final String KEY_SERVERS = "keyServers";
} }
public static final class defaults { public static final class Defaults {
public static final String KEY_SERVERS = "pool.sks-keyservers.net, subkeys.pgp.net, pgp.mit.edu"; public static final String KEY_SERVERS = "pool.sks-keyservers.net, subkeys.pgp.net, pgp.mit.edu";
} }

View File

@ -64,7 +64,7 @@ public class KeychainApplication extends Application {
// Create APG directory on sdcard if not existing // Create APG directory on sdcard if not existing
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dir = new File(Constants.path.APP_DIR); File dir = new File(Constants.Path.APP_DIR);
if (!dir.exists() && !dir.mkdirs()) { if (!dir.exists() && !dir.mkdirs()) {
// ignore this for now, it's not crucial // ignore this for now, it's not crucial
// that the directory doesn't exist at this point // that the directory doesn't exist at this point

View File

@ -37,8 +37,9 @@ import android.os.Handler;
* </code> * </code>
*/ */
public class DialogFragmentWorkaround { public class DialogFragmentWorkaround {
public static final SDKLevel17Interface INTERFACE = ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) ? new SDKLevel17Impl() public static final SDKLevel17Interface INTERFACE =
: new SDKLevelPriorLevel17Impl()); ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) ? new SDKLevel17Impl()
: new SDKLevelPriorLevel17Impl());
private static final int RUNNABLE_DELAY = 300; private static final int RUNNABLE_DELAY = 300;

View File

@ -17,24 +17,23 @@
package org.sufficientlysecure.keychain.helper; package org.sufficientlysecure.keychain.helper;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity; import android.app.Activity;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
public class ActionBarHelper { public class ActionBarHelper {
/** /**
* Set actionbar without home button if called from another app * Set actionbar without home button if called from another app
* *
* @param activity * @param activity
*/ */
public static void setBackButton(ActionBarActivity activity) { public static void setBackButton(ActionBarActivity activity) {
@ -54,7 +53,7 @@ public class ActionBarHelper {
/** /**
* Sets custom view on ActionBar for Done/Cancel activities * Sets custom view on ActionBar for Done/Cancel activities
* *
* @param actionBar * @param actionBar
* @param firstText * @param firstText
* @param firstDrawableId * @param firstDrawableId
@ -63,9 +62,9 @@ public class ActionBarHelper {
* @param secondDrawableId * @param secondDrawableId
* @param secondOnClickListener * @param secondOnClickListener
*/ */
public static void setTwoButtonView(ActionBar actionBar, int firstText, int firstDrawableId, public static void setTwoButtonView(ActionBar actionBar,
OnClickListener firstOnClickListener, int secondText, int secondDrawableId, int firstText, int firstDrawableId, OnClickListener firstOnClickListener,
OnClickListener secondOnClickListener) { int secondText, int secondDrawableId, OnClickListener secondOnClickListener) {
// Inflate the custom action bar view // Inflate the custom action bar view
final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext() final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext()
@ -94,13 +93,13 @@ public class ActionBarHelper {
/** /**
* Sets custom view on ActionBar for Done activities * Sets custom view on ActionBar for Done activities
* *
* @param actionBar * @param actionBar
* @param firstText * @param firstText
* @param firstOnClickListener * @param firstOnClickListener
*/ */
public static void setOneButtonView(ActionBar actionBar, int firstText, int firstDrawableId, public static void setOneButtonView(ActionBar actionBar, int firstText, int firstDrawableId,
OnClickListener firstOnClickListener) { OnClickListener firstOnClickListener) {
// Inflate a "Done" custom action bar view to serve as the "Up" affordance. // Inflate a "Done" custom action bar view to serve as the "Up" affordance.
final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext() final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext()
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE); .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

View File

@ -16,6 +16,16 @@
package org.sufficientlysecure.keychain.helper; 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.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@ -26,25 +36,15 @@ import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
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.v7.app.ActionBarActivity;
import android.widget.Toast;
public class ExportHelper { public class ExportHelper {
protected FileDialogFragment mFileDialog; protected FileDialogFragment mFileDialog;
protected String mExportFilename; protected String mExportFilename;
ActionBarActivity activity; ActionBarActivity mActivity;
public ExportHelper(ActionBarActivity activity) { public ExportHelper(ActionBarActivity activity) {
super(); super();
this.activity = activity; this.mActivity = activity;
} }
public void deleteKey(Uri dataUri, final int keyType, Handler deleteHandler) { public void deleteKey(Uri dataUri, final int keyType, Handler deleteHandler) {
@ -54,16 +54,16 @@ public class ExportHelper {
Messenger messenger = new Messenger(deleteHandler); Messenger messenger = new Messenger(deleteHandler);
DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
new long[] { keyRingRowId }, keyType); new long[]{keyRingRowId}, keyType);
deleteKeyDialog.show(activity.getSupportFragmentManager(), "deleteKeyDialog"); deleteKeyDialog.show(mActivity.getSupportFragmentManager(), "deleteKeyDialog");
} }
/** /**
* Show dialog where to export keys * Show dialog where to export keys
*/ */
public void showExportKeysDialog(final long[] rowIds, final int keyType, public void showExportKeysDialog(final long[] rowIds, final int keyType,
final String exportFilename) { final String exportFilename) {
mExportFilename = exportFilename; mExportFilename = exportFilename;
// Message is received after file is selected // Message is received after file is selected
@ -87,23 +87,23 @@ public class ExportHelper {
String title = null; String title = null;
if (rowIds == null) { if (rowIds == null) {
// export all keys // export all keys
title = activity.getString(R.string.title_export_keys); title = mActivity.getString(R.string.title_export_keys);
} else { } else {
// export only key specified at data uri // export only key specified at data uri
title = activity.getString(R.string.title_export_key); title = mActivity.getString(R.string.title_export_key);
} }
String message = null; String message = null;
if (keyType == Id.type.public_key) { if (keyType == Id.type.public_key) {
message = activity.getString(R.string.specify_file_to_export_to); message = mActivity.getString(R.string.specify_file_to_export_to);
} else { } else {
message = activity.getString(R.string.specify_file_to_export_secret_keys_to); message = mActivity.getString(R.string.specify_file_to_export_secret_keys_to);
} }
mFileDialog = FileDialogFragment.newInstance(messenger, title, message, mFileDialog = FileDialogFragment.newInstance(messenger, title, message,
exportFilename, null); exportFilename, null);
mFileDialog.show(activity.getSupportFragmentManager(), "fileDialog"); mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog");
} }
}); });
} }
@ -115,7 +115,7 @@ public class ExportHelper {
Log.d(Constants.TAG, "exportKeys started"); Log.d(Constants.TAG, "exportKeys started");
// Send all information needed to service to export key in other thread // Send all information needed to service to export key in other thread
Intent intent = new Intent(activity, KeychainIntentService.class); final Intent intent = new Intent(mActivity, KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_EXPORT_KEYRING); intent.setAction(KeychainIntentService.ACTION_EXPORT_KEYRING);
@ -134,8 +134,16 @@ public class ExportHelper {
intent.putExtra(KeychainIntentService.EXTRA_DATA, data); intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
// Message is received after exporting is done in ApgService // Message is received after exporting is done in ApgService
KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(activity, KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(mActivity,
activity.getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) { 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) { public void handleMessage(Message message) {
// handle messages by standard ApgHandler first // handle messages by standard ApgHandler first
super.handleMessage(message); super.handleMessage(message);
@ -147,13 +155,13 @@ public class ExportHelper {
int exported = returnData.getInt(KeychainIntentService.RESULT_EXPORT); int exported = returnData.getInt(KeychainIntentService.RESULT_EXPORT);
String toastMessage; String toastMessage;
if (exported == 1) { if (exported == 1) {
toastMessage = activity.getString(R.string.key_exported); toastMessage = mActivity.getString(R.string.key_exported);
} else if (exported > 0) { } else if (exported > 0) {
toastMessage = activity.getString(R.string.keys_exported, exported); toastMessage = mActivity.getString(R.string.keys_exported, exported);
} else { } else {
toastMessage = activity.getString(R.string.no_keys_exported); toastMessage = mActivity.getString(R.string.no_keys_exported);
} }
Toast.makeText(activity, toastMessage, Toast.LENGTH_SHORT).show(); Toast.makeText(mActivity, toastMessage, Toast.LENGTH_SHORT).show();
} }
} }
@ -164,10 +172,10 @@ public class ExportHelper {
intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
// show progress dialog // show progress dialog
exportHandler.showProgressDialog(activity); exportHandler.showProgressDialog(mActivity);
// start service with intent // start service with intent
activity.startService(intent); mActivity.startService(intent);
} }
} }

View File

@ -17,10 +17,6 @@
package org.sufficientlysecure.keychain.helper; package org.sufficientlysecure.keychain.helper;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity; import android.app.Activity;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.Context; import android.content.Context;
@ -30,12 +26,15 @@ import android.net.Uri;
import android.os.Environment; import android.os.Environment;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.widget.Toast; import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
public class FileHelper { public class FileHelper {
/** /**
* Checks if external storage is mounted if file is located on external storage * Checks if external storage is mounted if file is located on external storage
* *
* @param file * @param file
* @return true if storage is mounted * @return true if storage is mounted
*/ */
@ -52,15 +51,12 @@ public class FileHelper {
/** /**
* Opens the preferred installed file manager on Android and shows a toast if no manager is * Opens the preferred installed file manager on Android and shows a toast if no manager is
* installed. * installed.
* *
* @param activity * @param activity
* @param filename * @param filename default selected file, not supported by all file managers
* default selected file, not supported by all file managers * @param mimeType can be text/plain for example
* @param mimeType * @param requestCode requestCode used to identify the result coming back from file manager to
* can be text/plain for example * onActivityResult() in your activity
* @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) { public static void openFile(Activity activity, String filename, String mimeType, int requestCode) {
Intent intent = buildFileIntent(filename, mimeType); Intent intent = buildFileIntent(filename, mimeType);
@ -97,14 +93,13 @@ public class FileHelper {
/** /**
* Get a file path from a Uri. * Get a file path from a Uri.
* * <p/>
* from https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/ * from https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/
* afilechooser/utils/FileUtils.java * afilechooser/utils/FileUtils.java
* *
* @param context * @param context
* @param uri * @param uri
* @return * @return
*
* @author paulburke * @author paulburke
*/ */
public static String getPath(Context context, Uri uri) { public static String getPath(Context context, Uri uri) {
@ -115,21 +110,19 @@ public class FileHelper {
+ uri.getPathSegments().toString()); + uri.getPathSegments().toString());
if ("content".equalsIgnoreCase(uri.getScheme())) { if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = { "_data" }; String[] projection = {"_data"};
Cursor cursor = null; Cursor cursor = null;
try { try {
cursor = context.getContentResolver().query(uri, projection, null, null, null); cursor = context.getContentResolver().query(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow("_data"); int columnIndex = cursor.getColumnIndexOrThrow("_data");
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
return cursor.getString(column_index); return cursor.getString(columnIndex);
} }
} catch (Exception e) { } catch (Exception e) {
// Eat it // Eat it
} }
} } else if ("file".equalsIgnoreCase(uri.getScheme())) {
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath(); return uri.getPath();
} }

View File

@ -17,19 +17,21 @@
package org.sufficientlysecure.keychain.helper; package org.sufficientlysecure.keychain.helper;
import java.util.Iterator; import android.os.Bundle;
import java.util.Set;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import android.os.Bundle; import java.security.DigestException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.Set;
public class OtherHelper { public class OtherHelper {
/** /**
* Logs bundle content to debug for inspecting the content * Logs bundle content to debug for inspecting the content
* *
* @param bundle * @param bundle
* @param bundleName * @param bundleName
*/ */
@ -58,4 +60,24 @@ public class OtherHelper {
} }
} }
/**
* 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 NoSuchAlgorithmException
* @throws DigestException
*/
public 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;
}
} }

View File

@ -17,14 +17,13 @@
package org.sufficientlysecure.keychain.helper; package org.sufficientlysecure.keychain.helper;
import android.content.Context;
import android.content.SharedPreferences;
import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData; import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import android.content.Context;
import android.content.SharedPreferences;
import java.util.Vector; import java.util.Vector;
/** /**
@ -38,8 +37,8 @@ public class Preferences {
return getPreferences(context, false); return getPreferences(context, false);
} }
public static synchronized Preferences getPreferences(Context context, boolean force_new) { public static synchronized Preferences getPreferences(Context context, boolean forceNew) {
if (mPreferences == null || force_new) { if (mPreferences == null || forceNew) {
mPreferences = new Preferences(context); mPreferences = new Preferences(context);
} }
return mPreferences; return mPreferences;
@ -50,17 +49,17 @@ public class Preferences {
} }
public String getLanguage() { public String getLanguage() {
return mSharedPreferences.getString(Constants.pref.LANGUAGE, ""); return mSharedPreferences.getString(Constants.Pref.LANGUAGE, "");
} }
public void setLanguage(String value) { public void setLanguage(String value) {
SharedPreferences.Editor editor = mSharedPreferences.edit(); SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(Constants.pref.LANGUAGE, value); editor.putString(Constants.Pref.LANGUAGE, value);
editor.commit(); editor.commit();
} }
public long getPassPhraseCacheTtl() { public long getPassPhraseCacheTtl() {
int ttl = mSharedPreferences.getInt(Constants.pref.PASS_PHRASE_CACHE_TTL, 180); int ttl = mSharedPreferences.getInt(Constants.Pref.PASS_PHRASE_CACHE_TTL, 180);
// fix the value if it was set to "never" in previous versions, which currently is not // fix the value if it was set to "never" in previous versions, which currently is not
// supported // supported
if (ttl == 0) { if (ttl == 0) {
@ -71,77 +70,77 @@ public class Preferences {
public void setPassPhraseCacheTtl(int value) { public void setPassPhraseCacheTtl(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit(); SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(Constants.pref.PASS_PHRASE_CACHE_TTL, value); editor.putInt(Constants.Pref.PASS_PHRASE_CACHE_TTL, value);
editor.commit(); editor.commit();
} }
public int getDefaultEncryptionAlgorithm() { public int getDefaultEncryptionAlgorithm() {
return mSharedPreferences.getInt(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM, return mSharedPreferences.getInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM,
PGPEncryptedData.AES_256); PGPEncryptedData.AES_256);
} }
public void setDefaultEncryptionAlgorithm(int value) { public void setDefaultEncryptionAlgorithm(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit(); SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM, value); editor.putInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM, value);
editor.commit(); editor.commit();
} }
public int getDefaultHashAlgorithm() { public int getDefaultHashAlgorithm() {
return mSharedPreferences.getInt(Constants.pref.DEFAULT_HASH_ALGORITHM, return mSharedPreferences.getInt(Constants.Pref.DEFAULT_HASH_ALGORITHM,
HashAlgorithmTags.SHA512); HashAlgorithmTags.SHA512);
} }
public void setDefaultHashAlgorithm(int value) { public void setDefaultHashAlgorithm(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit(); SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(Constants.pref.DEFAULT_HASH_ALGORITHM, value); editor.putInt(Constants.Pref.DEFAULT_HASH_ALGORITHM, value);
editor.commit(); editor.commit();
} }
public int getDefaultMessageCompression() { public int getDefaultMessageCompression() {
return mSharedPreferences.getInt(Constants.pref.DEFAULT_MESSAGE_COMPRESSION, return mSharedPreferences.getInt(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION,
Id.choice.compression.zlib); Id.choice.compression.zlib);
} }
public void setDefaultMessageCompression(int value) { public void setDefaultMessageCompression(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit(); SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(Constants.pref.DEFAULT_MESSAGE_COMPRESSION, value); editor.putInt(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION, value);
editor.commit(); editor.commit();
} }
public int getDefaultFileCompression() { public int getDefaultFileCompression() {
return mSharedPreferences.getInt(Constants.pref.DEFAULT_FILE_COMPRESSION, return mSharedPreferences.getInt(Constants.Pref.DEFAULT_FILE_COMPRESSION,
Id.choice.compression.none); Id.choice.compression.none);
} }
public void setDefaultFileCompression(int value) { public void setDefaultFileCompression(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit(); SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(Constants.pref.DEFAULT_FILE_COMPRESSION, value); editor.putInt(Constants.Pref.DEFAULT_FILE_COMPRESSION, value);
editor.commit(); editor.commit();
} }
public boolean getDefaultAsciiArmour() { public boolean getDefaultAsciiArmour() {
return mSharedPreferences.getBoolean(Constants.pref.DEFAULT_ASCII_ARMOUR, false); return mSharedPreferences.getBoolean(Constants.Pref.DEFAULT_ASCII_ARMOUR, false);
} }
public void setDefaultAsciiArmour(boolean value) { public void setDefaultAsciiArmour(boolean value) {
SharedPreferences.Editor editor = mSharedPreferences.edit(); SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putBoolean(Constants.pref.DEFAULT_ASCII_ARMOUR, value); editor.putBoolean(Constants.Pref.DEFAULT_ASCII_ARMOUR, value);
editor.commit(); editor.commit();
} }
public boolean getForceV3Signatures() { public boolean getForceV3Signatures() {
return mSharedPreferences.getBoolean(Constants.pref.FORCE_V3_SIGNATURES, false); return mSharedPreferences.getBoolean(Constants.Pref.FORCE_V3_SIGNATURES, false);
} }
public void setForceV3Signatures(boolean value) { public void setForceV3Signatures(boolean value) {
SharedPreferences.Editor editor = mSharedPreferences.edit(); SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putBoolean(Constants.pref.FORCE_V3_SIGNATURES, value); editor.putBoolean(Constants.Pref.FORCE_V3_SIGNATURES, value);
editor.commit(); editor.commit();
} }
public String[] getKeyServers() { public String[] getKeyServers() {
String rawData = mSharedPreferences.getString(Constants.pref.KEY_SERVERS, String rawData = mSharedPreferences.getString(Constants.Pref.KEY_SERVERS,
Constants.defaults.KEY_SERVERS); Constants.Defaults.KEY_SERVERS);
Vector<String> servers = new Vector<String>(); Vector<String> servers = new Vector<String>();
String chunks[] = rawData.split(","); String chunks[] = rawData.split(",");
for (String c : chunks) { for (String c : chunks) {
@ -166,7 +165,7 @@ public class Preferences {
} }
rawData += tmp; rawData += tmp;
} }
editor.putString(Constants.pref.KEY_SERVERS, rawData); editor.putString(Constants.Pref.KEY_SERVERS, rawData);
editor.commit(); editor.commit();
} }
} }

View File

@ -17,11 +17,6 @@
package org.sufficientlysecure.keychain.pgp; package org.sufficientlysecure.keychain.pgp;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
@ -31,12 +26,17 @@ import org.spongycastle.openpgp.PGPSignatureList;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log; 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 { public class PgpConversionHelper {
/** /**
* Convert from byte[] to PGPKeyRing * Convert from byte[] to PGPKeyRing
* *
* @param keysBytes * @param keysBytes
* @return * @return
*/ */
@ -56,7 +56,7 @@ public class PgpConversionHelper {
/** /**
* Convert from byte[] to ArrayList<PGPSecretKey> * Convert from byte[] to ArrayList<PGPSecretKey>
* *
* @param keysBytes * @param keysBytes
* @return * @return
*/ */
@ -75,9 +75,9 @@ public class PgpConversionHelper {
/** /**
* Convert from byte[] to PGPSecretKey * Convert from byte[] to PGPSecretKey
* * <p/>
* Singles keys are encoded as keyRings with one single key in it by Bouncy Castle * Singles keys are encoded as keyRings with one single key in it by Bouncy Castle
* *
* @param keyBytes * @param keyBytes
* @return * @return
*/ */
@ -90,13 +90,13 @@ public class PgpConversionHelper {
Log.e(Constants.TAG, "Error while converting to PGPSecretKey!", e); Log.e(Constants.TAG, "Error while converting to PGPSecretKey!", e);
} }
PGPSecretKey secKey = null; PGPSecretKey secKey = null;
if(obj instanceof PGPSecretKey) { if (obj instanceof PGPSecretKey) {
if ((secKey = (PGPSecretKey)obj ) == null) { if ((secKey = (PGPSecretKey) obj) == null) {
Log.e(Constants.TAG, "No keys given!"); Log.e(Constants.TAG, "No keys given!");
} }
} else if(obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings } else if (obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings
PGPSecretKeyRing keyRing = null; PGPSecretKeyRing keyRing = null;
if ((keyRing = (PGPSecretKeyRing)obj) == null) { if ((keyRing = (PGPSecretKeyRing) obj) == null) {
Log.e(Constants.TAG, "No keys given!"); Log.e(Constants.TAG, "No keys given!");
} }
secKey = keyRing.getSecretKey(); secKey = keyRing.getSecretKey();
@ -129,7 +129,7 @@ public class PgpConversionHelper {
/** /**
* Convert from ArrayList<PGPSecretKey> to byte[] * Convert from ArrayList<PGPSecretKey> to byte[]
* *
* @param keys * @param keys
* @return * @return
*/ */
@ -148,7 +148,7 @@ public class PgpConversionHelper {
/** /**
* Convert from PGPSecretKey to byte[] * Convert from PGPSecretKey to byte[]
* *
* @param key * @param key
* @return * @return
*/ */
@ -164,7 +164,7 @@ public class PgpConversionHelper {
/** /**
* Convert from PGPSecretKeyRing to byte[] * Convert from PGPSecretKeyRing to byte[]
* *
* @param keyRing * @param keyRing
* @return * @return
*/ */

View File

@ -18,38 +18,16 @@
package org.sufficientlysecure.keychain.pgp; package org.sufficientlysecure.keychain.pgp;
import android.content.Context; import android.content.Context;
import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.bcpg.ArmoredInputStream; import org.spongycastle.bcpg.ArmoredInputStream;
import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.bcpg.SignatureSubpacketTags;
import org.spongycastle.openpgp.PGPCompressedData; import org.spongycastle.openpgp.*;
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.PGPUtil;
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory; import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.spongycastle.openpgp.operator.jcajce.*;
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.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
@ -59,12 +37,7 @@ import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import java.io.BufferedInputStream; import java.io.*;
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.security.SignatureException;
import java.util.Iterator; import java.util.Iterator;
@ -72,57 +45,57 @@ import java.util.Iterator;
* This class uses a Builder pattern! * This class uses a Builder pattern!
*/ */
public class PgpDecryptVerify { public class PgpDecryptVerify {
private Context context; private Context mContext;
private InputData data; private InputData mData;
private OutputStream outStream; private OutputStream mOutStream;
private ProgressDialogUpdater progressDialogUpdater; private ProgressDialogUpdater mProgressDialogUpdater;
private boolean assumeSymmetric; private boolean mAssumeSymmetric;
private String passphrase; private String mPassphrase;
private long enforcedKeyId; private long mEnforcedKeyId;
private PgpDecryptVerify(Builder builder) { private PgpDecryptVerify(Builder builder) {
// private Constructor can only be called from Builder // private Constructor can only be called from Builder
this.context = builder.context; this.mContext = builder.mContext;
this.data = builder.data; this.mData = builder.mData;
this.outStream = builder.outStream; this.mOutStream = builder.mOutStream;
this.progressDialogUpdater = builder.progressDialogUpdater; this.mProgressDialogUpdater = builder.mProgressDialogUpdater;
this.assumeSymmetric = builder.assumeSymmetric; this.mAssumeSymmetric = builder.mAssumeSymmetric;
this.passphrase = builder.passphrase; this.mPassphrase = builder.mPassphrase;
this.enforcedKeyId = builder.enforcedKeyId; this.mEnforcedKeyId = builder.mEnforcedKeyId;
} }
public static class Builder { public static class Builder {
// mandatory parameter // mandatory parameter
private Context context; private Context mContext;
private InputData data; private InputData mData;
private OutputStream outStream; private OutputStream mOutStream;
// optional // optional
private ProgressDialogUpdater progressDialogUpdater = null; private ProgressDialogUpdater mProgressDialogUpdater = null;
private boolean assumeSymmetric = false; private boolean mAssumeSymmetric = false;
private String passphrase = ""; private String mPassphrase = "";
private long enforcedKeyId = 0; private long mEnforcedKeyId = 0;
public Builder(Context context, InputData data, OutputStream outStream) { public Builder(Context context, InputData data, OutputStream outStream) {
this.context = context; this.mContext = context;
this.data = data; this.mData = data;
this.outStream = outStream; this.mOutStream = outStream;
} }
public Builder progressDialogUpdater(ProgressDialogUpdater progressDialogUpdater) { public Builder progressDialogUpdater(ProgressDialogUpdater progressDialogUpdater) {
this.progressDialogUpdater = progressDialogUpdater; this.mProgressDialogUpdater = progressDialogUpdater;
return this; return this;
} }
public Builder assumeSymmetric(boolean assumeSymmetric) { public Builder assumeSymmetric(boolean assumeSymmetric) {
this.assumeSymmetric = assumeSymmetric; this.mAssumeSymmetric = assumeSymmetric;
return this; return this;
} }
public Builder passphrase(String passphrase) { public Builder passphrase(String passphrase) {
this.passphrase = passphrase; this.mPassphrase = passphrase;
return this; return this;
} }
@ -134,7 +107,7 @@ public class PgpDecryptVerify {
* @return * @return
*/ */
public Builder enforcedKeyId(long enforcedKeyId) { public Builder enforcedKeyId(long enforcedKeyId) {
this.enforcedKeyId = enforcedKeyId; this.mEnforcedKeyId = enforcedKeyId;
return this; return this;
} }
@ -144,14 +117,14 @@ public class PgpDecryptVerify {
} }
public void updateProgress(int message, int current, int total) { public void updateProgress(int message, int current, int total) {
if (progressDialogUpdater != null) { if (mProgressDialogUpdater != null) {
progressDialogUpdater.setProgress(message, current, total); mProgressDialogUpdater.setProgress(message, current, total);
} }
} }
public void updateProgress(int current, int total) { public void updateProgress(int current, int total) {
if (progressDialogUpdater != null) { if (mProgressDialogUpdater != null) {
progressDialogUpdater.setProgress(current, total); mProgressDialogUpdater.setProgress(current, total);
} }
} }
@ -196,7 +169,7 @@ public class PgpDecryptVerify {
public PgpDecryptVerifyResult execute() public PgpDecryptVerifyResult execute()
throws IOException, PgpGeneralException, PGPException, SignatureException { throws IOException, PgpGeneralException, PGPException, SignatureException {
// automatically works with ascii armor input and binary // automatically works with ascii armor input and binary
InputStream in = PGPUtil.getDecoderStream(data.getInputStream()); InputStream in = PGPUtil.getDecoderStream(mData.getInputStream());
if (in instanceof ArmoredInputStream) { if (in instanceof ArmoredInputStream) {
ArmoredInputStream aIn = (ArmoredInputStream) in; ArmoredInputStream aIn = (ArmoredInputStream) in;
// it is ascii armored // it is ascii armored
@ -240,7 +213,7 @@ public class PgpDecryptVerify {
} }
if (enc == null) { if (enc == null) {
throw new PgpGeneralException(context.getString(R.string.error_invalid_data)); throw new PgpGeneralException(mContext.getString(R.string.error_invalid_data));
} }
InputStream clear; InputStream clear;
@ -250,7 +223,7 @@ public class PgpDecryptVerify {
// TODO: currently we always only look at the first known key or symmetric encryption, // TODO: currently we always only look at the first known key or symmetric encryption,
// there might be more... // there might be more...
if (assumeSymmetric) { if (mAssumeSymmetric) {
PGPPBEEncryptedData pbe = null; PGPPBEEncryptedData pbe = null;
Iterator<?> it = enc.getEncryptedDataObjects(); Iterator<?> it = enc.getEncryptedDataObjects();
// find secret key // find secret key
@ -264,7 +237,7 @@ public class PgpDecryptVerify {
if (pbe == null) { if (pbe == null) {
throw new PgpGeneralException( throw new PgpGeneralException(
context.getString(R.string.error_no_symmetric_encryption_packet)); mContext.getString(R.string.error_no_symmetric_encryption_packet));
} }
updateProgress(R.string.progress_preparing_streams, currentProgress, 100); updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
@ -273,7 +246,7 @@ public class PgpDecryptVerify {
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder( PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
passphrase.toCharArray()); mPassphrase.toCharArray());
clear = pbe.getDataStream(decryptorFactory); clear = pbe.getDataStream(decryptorFactory);
@ -290,33 +263,37 @@ public class PgpDecryptVerify {
Object obj = it.next(); Object obj = it.next();
if (obj instanceof PGPPublicKeyEncryptedData) { if (obj instanceof PGPPublicKeyEncryptedData) {
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj; PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, encData.getKeyID()); secretKey = ProviderHelper.getPGPSecretKeyByKeyId(mContext, encData.getKeyID());
if (secretKey != null) { if (secretKey != null) {
// secret key exists in database // secret key exists in database
// allow only a specific key for decryption? // allow only a specific key for decryption?
if (enforcedKeyId != 0) { if (mEnforcedKeyId != 0) {
// TODO: improve this code! get master key directly! // TODO: improve this code! get master key directly!
PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, encData.getKeyID()); PGPSecretKeyRing secretKeyRing =
ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, encData.getKeyID());
long masterKeyId = PgpKeyHelper.getMasterKey(secretKeyRing).getKeyID(); long masterKeyId = PgpKeyHelper.getMasterKey(secretKeyRing).getKeyID();
Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID()); Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID());
Log.d(Constants.TAG, "enforcedKeyId: " + enforcedKeyId); Log.d(Constants.TAG, "enforcedKeyId: " + mEnforcedKeyId);
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId); Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
if (enforcedKeyId != masterKeyId) { if (mEnforcedKeyId != masterKeyId) {
throw new PgpGeneralException(context.getString(R.string.error_no_secret_key_found)); throw new PgpGeneralException(
mContext.getString(R.string.error_no_secret_key_found));
} }
} }
pbe = encData; pbe = encData;
// if no passphrase was explicitly set try to get it from the cache service // if no passphrase was explicitly set try to get it from the cache service
if (passphrase == null) { if (mPassphrase == null) {
// returns "" if key has no passphrase // returns "" if key has no passphrase
passphrase = PassphraseCacheService.getCachedPassphrase(context, encData.getKeyID()); mPassphrase =
PassphraseCacheService.getCachedPassphrase(mContext, encData.getKeyID());
// if passphrase was not cached, return here indicating that a passphrase is missing! // if passphrase was not cached, return here
if (passphrase == null) { // indicating that a passphrase is missing!
if (mPassphrase == null) {
returnData.setKeyPassphraseNeeded(true); returnData.setKeyPassphraseNeeded(true);
return returnData; return returnData;
} }
@ -330,7 +307,7 @@ public class PgpDecryptVerify {
} }
if (secretKey == null) { if (secretKey == null) {
throw new PgpGeneralException(context.getString(R.string.error_no_secret_key_found)); throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
} }
currentProgress += 5; currentProgress += 5;
@ -339,14 +316,14 @@ public class PgpDecryptVerify {
try { try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
passphrase.toCharArray()); mPassphrase.toCharArray());
privateKey = secretKey.extractPrivateKey(keyDecryptor); privateKey = secretKey.extractPrivateKey(keyDecryptor);
} catch (PGPException e) { } catch (PGPException e) {
throw new PGPException(context.getString(R.string.error_wrong_passphrase)); throw new PGPException(mContext.getString(R.string.error_wrong_passphrase));
} }
if (privateKey == null) { if (privateKey == null) {
throw new PgpGeneralException( throw new PgpGeneralException(
context.getString(R.string.error_could_not_extract_private_key)); mContext.getString(R.string.error_could_not_extract_private_key));
} }
currentProgress += 5; currentProgress += 5;
updateProgress(R.string.progress_preparing_streams, currentProgress, 100); updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
@ -386,7 +363,7 @@ public class PgpDecryptVerify {
for (int i = 0; i < sigList.size(); ++i) { for (int i = 0; i < sigList.size(); ++i) {
signature = sigList.get(i); signature = sigList.get(i);
signatureKey = ProviderHelper signatureKey = ProviderHelper
.getPGPPublicKeyByKeyId(context, signature.getKeyID()); .getPGPPublicKeyByKeyId(mContext, signature.getKeyID());
if (signatureKeyId == 0) { if (signatureKeyId == 0) {
signatureKeyId = signature.getKeyID(); signatureKeyId = signature.getKeyID();
} }
@ -397,7 +374,7 @@ public class PgpDecryptVerify {
signatureKeyId = signature.getKeyID(); signatureKeyId = signature.getKeyID();
String userId = null; String userId = null;
PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId( PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(
context, signatureKeyId); mContext, signatureKeyId);
if (signKeyRing != null) { if (signKeyRing != null) {
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing)); userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
} }
@ -409,7 +386,8 @@ public class PgpDecryptVerify {
signatureResult.setKeyId(signatureKeyId); signatureResult.setKeyId(signatureKeyId);
if (signature != null) { if (signature != null) {
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
new JcaPGPContentVerifierBuilderProvider()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
signature.init(contentVerifierBuilderProvider, signatureKey); signature.init(contentVerifierBuilderProvider, signatureKey);
@ -444,9 +422,9 @@ public class PgpDecryptVerify {
int n; int n;
// TODO: progress calculation is broken here! Try to rework it based on commented code! // TODO: progress calculation is broken here! Try to rework it based on commented code!
// int progress = 0; // int progress = 0;
long startPos = data.getStreamPosition(); long startPos = mData.getStreamPosition();
while ((n = dataIn.read(buffer)) > 0) { while ((n = dataIn.read(buffer)) > 0) {
outStream.write(buffer, 0, n); mOutStream.write(buffer, 0, n);
// progress += n; // progress += n;
if (signature != null) { if (signature != null) {
try { try {
@ -460,11 +438,11 @@ public class PgpDecryptVerify {
// unknown size, but try to at least have a moving, slowing down progress bar // unknown size, but try to at least have a moving, slowing down progress bar
// currentProgress = startProgress + (endProgress - startProgress) * progress // currentProgress = startProgress + (endProgress - startProgress) * progress
// / (progress + 100000); // / (progress + 100000);
if (data.getSize() - startPos == 0) { if (mData.getSize() - startPos == 0) {
currentProgress = endProgress; currentProgress = endProgress;
} else { } else {
currentProgress = (int) (startProgress + (endProgress - startProgress) currentProgress = (int) (startProgress + (endProgress - startProgress)
* (data.getStreamPosition() - startPos) / (data.getSize() - startPos)); * (mData.getStreamPosition() - startPos) / (mData.getSize() - startPos));
} }
updateProgress(currentProgress, 100); updateProgress(currentProgress, 100);
} }
@ -480,7 +458,7 @@ public class PgpDecryptVerify {
signatureResult.setSignatureOnly(false); signatureResult.setSignatureOnly(false);
//Now check binding signatures //Now check binding signatures
boolean validKeyBinding = verifyKeyBinding(context, messageSignature, signatureKey); boolean validKeyBinding = verifyKeyBinding(mContext, messageSignature, signatureKey);
boolean validSignature = signature.verify(messageSignature); boolean validSignature = signature.verify(messageSignature);
// TODO: implement CERTIFIED! // TODO: implement CERTIFIED!
@ -499,7 +477,7 @@ public class PgpDecryptVerify {
} else { } else {
// failed // failed
Log.d(Constants.TAG, "Integrity verification: failed!"); Log.d(Constants.TAG, "Integrity verification: failed!");
throw new PgpGeneralException(context.getString(R.string.error_integrity_check_failed)); throw new PgpGeneralException(mContext.getString(R.string.error_integrity_check_failed));
} }
} else { } else {
// no integrity check // no integrity check
@ -555,21 +533,21 @@ public class PgpDecryptVerify {
out.close(); out.close();
byte[] clearText = out.toByteArray(); byte[] clearText = out.toByteArray();
outStream.write(clearText); mOutStream.write(clearText);
updateProgress(R.string.progress_processing_signature, 60, 100); updateProgress(R.string.progress_processing_signature, 60, 100);
PGPObjectFactory pgpFact = new PGPObjectFactory(aIn); PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject(); PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject();
if (sigList == null) { if (sigList == null) {
throw new PgpGeneralException(context.getString(R.string.error_corrupt_data)); throw new PgpGeneralException(mContext.getString(R.string.error_corrupt_data));
} }
PGPSignature signature = null; PGPSignature signature = null;
long signatureKeyId = 0; long signatureKeyId = 0;
PGPPublicKey signatureKey = null; PGPPublicKey signatureKey = null;
for (int i = 0; i < sigList.size(); ++i) { for (int i = 0; i < sigList.size(); ++i) {
signature = sigList.get(i); signature = sigList.get(i);
signatureKey = ProviderHelper.getPGPPublicKeyByKeyId(context, signature.getKeyID()); signatureKey = ProviderHelper.getPGPPublicKeyByKeyId(mContext, signature.getKeyID());
if (signatureKeyId == 0) { if (signatureKeyId == 0) {
signatureKeyId = signature.getKeyID(); signatureKeyId = signature.getKeyID();
} }
@ -579,7 +557,7 @@ public class PgpDecryptVerify {
} else { } else {
signatureKeyId = signature.getKeyID(); signatureKeyId = signature.getKeyID();
String userId = null; String userId = null;
PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context, PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(mContext,
signatureKeyId); signatureKeyId);
if (signKeyRing != null) { if (signKeyRing != null) {
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing)); userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
@ -623,7 +601,7 @@ public class PgpDecryptVerify {
} }
//Now check binding signatures //Now check binding signatures
boolean validKeyBinding = verifyKeyBinding(context, signature, signatureKey); boolean validKeyBinding = verifyKeyBinding(mContext, signature, signatureKey);
boolean validSignature = signature.verify(); boolean validSignature = signature.verify();
if (validSignature & validKeyBinding) { if (validSignature & validKeyBinding) {
@ -638,7 +616,8 @@ public class PgpDecryptVerify {
return returnData; return returnData;
} }
private static boolean verifyKeyBinding(Context context, PGPSignature signature, PGPPublicKey signatureKey) { private static boolean verifyKeyBinding(Context context,
PGPSignature signature, PGPPublicKey signatureKey) {
long signatureKeyId = signature.getKeyID(); long signatureKeyId = signature.getKeyID();
boolean validKeyBinding = false; boolean validKeyBinding = false;
@ -673,7 +652,8 @@ public class PgpDecryptVerify {
//about keys without subkey signing. Can't get it to import a slightly broken one //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. //either, so we will err on bad subkey binding here.
PGPSignature sig = itr.next(); PGPSignature sig = itr.next();
if (sig.getKeyID() == masterPublicKey.getKeyID() && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) { if (sig.getKeyID() == masterPublicKey.getKeyID() &&
sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
//check and if ok, check primary key binding. //check and if ok, check primary key binding.
try { try {
sig.init(contentVerifierBuilderProvider, masterPublicKey); sig.init(contentVerifierBuilderProvider, masterPublicKey);
@ -684,34 +664,37 @@ public class PgpDecryptVerify {
continue; continue;
} }
if (validTempSubkeyBinding) if (validTempSubkeyBinding) {
validSubkeyBinding = true; validSubkeyBinding = true;
}
if (validTempSubkeyBinding) { if (validTempSubkeyBinding) {
validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(), validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(),
masterPublicKey, signingPublicKey); masterPublicKey, signingPublicKey);
if (validPrimaryKeyBinding) if (validPrimaryKeyBinding) {
break; break;
}
validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(), validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(),
masterPublicKey, signingPublicKey); masterPublicKey, signingPublicKey);
if (validPrimaryKeyBinding) if (validPrimaryKeyBinding) {
break; break;
}
} }
} }
} }
return (validSubkeyBinding & validPrimaryKeyBinding); return (validSubkeyBinding & validPrimaryKeyBinding);
} }
private static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector Pkts, private static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts,
PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
boolean validPrimaryKeyBinding = false; boolean validPrimaryKeyBinding = false;
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
new JcaPGPContentVerifierBuilderProvider() new JcaPGPContentVerifierBuilderProvider()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureList eSigList; PGPSignatureList eSigList;
if (Pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) { if (pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
try { try {
eSigList = Pkts.getEmbeddedSignatures(); eSigList = pkts.getEmbeddedSignatures();
} catch (IOException e) { } catch (IOException e) {
return false; return false;
} catch (PGPException e) { } catch (PGPException e) {
@ -723,8 +706,9 @@ public class PgpDecryptVerify {
try { try {
emSig.init(contentVerifierBuilderProvider, signingPublicKey); emSig.init(contentVerifierBuilderProvider, signingPublicKey);
validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey); validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey);
if (validPrimaryKeyBinding) if (validPrimaryKeyBinding) {
break; break;
}
} catch (PGPException e) { } catch (PGPException e) {
continue; continue;
} catch (SignatureException e) { } catch (SignatureException e) {

View File

@ -19,36 +19,35 @@ package org.sufficientlysecure.keychain.pgp;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.OpenPgpSignatureResult;
public class PgpDecryptVerifyResult implements Parcelable { public class PgpDecryptVerifyResult implements Parcelable {
boolean symmetricPassphraseNeeded; boolean mSymmetricPassphraseNeeded;
boolean keyPassphraseNeeded; boolean mKeyPassphraseNeeded;
OpenPgpSignatureResult signatureResult; OpenPgpSignatureResult mSignatureResult;
public boolean isSymmetricPassphraseNeeded() { public boolean isSymmetricPassphraseNeeded() {
return symmetricPassphraseNeeded; return mSymmetricPassphraseNeeded;
} }
public void setSymmetricPassphraseNeeded(boolean symmetricPassphraseNeeded) { public void setSymmetricPassphraseNeeded(boolean symmetricPassphraseNeeded) {
this.symmetricPassphraseNeeded = symmetricPassphraseNeeded; this.mSymmetricPassphraseNeeded = symmetricPassphraseNeeded;
} }
public boolean isKeyPassphraseNeeded() { public boolean isKeyPassphraseNeeded() {
return keyPassphraseNeeded; return mKeyPassphraseNeeded;
} }
public void setKeyPassphraseNeeded(boolean keyPassphraseNeeded) { public void setKeyPassphraseNeeded(boolean keyPassphraseNeeded) {
this.keyPassphraseNeeded = keyPassphraseNeeded; this.mKeyPassphraseNeeded = keyPassphraseNeeded;
} }
public OpenPgpSignatureResult getSignatureResult() { public OpenPgpSignatureResult getSignatureResult() {
return signatureResult; return mSignatureResult;
} }
public void setSignatureResult(OpenPgpSignatureResult signatureResult) { public void setSignatureResult(OpenPgpSignatureResult signatureResult) {
this.signatureResult = signatureResult; this.mSignatureResult = signatureResult;
} }
public PgpDecryptVerifyResult() { public PgpDecryptVerifyResult() {
@ -56,9 +55,9 @@ public class PgpDecryptVerifyResult implements Parcelable {
} }
public PgpDecryptVerifyResult(PgpDecryptVerifyResult b) { public PgpDecryptVerifyResult(PgpDecryptVerifyResult b) {
this.symmetricPassphraseNeeded = b.symmetricPassphraseNeeded; this.mSymmetricPassphraseNeeded = b.mSymmetricPassphraseNeeded;
this.keyPassphraseNeeded = b.keyPassphraseNeeded; this.mKeyPassphraseNeeded = b.mKeyPassphraseNeeded;
this.signatureResult = b.signatureResult; this.mSignatureResult = b.mSignatureResult;
} }
@ -67,17 +66,17 @@ public class PgpDecryptVerifyResult implements Parcelable {
} }
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeByte((byte) (symmetricPassphraseNeeded ? 1 : 0)); dest.writeByte((byte) (mSymmetricPassphraseNeeded ? 1 : 0));
dest.writeByte((byte) (keyPassphraseNeeded ? 1 : 0)); dest.writeByte((byte) (mKeyPassphraseNeeded ? 1 : 0));
dest.writeParcelable(signatureResult, 0); dest.writeParcelable(mSignatureResult, 0);
} }
public static final Creator<PgpDecryptVerifyResult> CREATOR = new Creator<PgpDecryptVerifyResult>() { public static final Creator<PgpDecryptVerifyResult> CREATOR = new Creator<PgpDecryptVerifyResult>() {
public PgpDecryptVerifyResult createFromParcel(final Parcel source) { public PgpDecryptVerifyResult createFromParcel(final Parcel source) {
PgpDecryptVerifyResult vr = new PgpDecryptVerifyResult(); PgpDecryptVerifyResult vr = new PgpDecryptVerifyResult();
vr.symmetricPassphraseNeeded = source.readByte() == 1; vr.mSymmetricPassphraseNeeded = source.readByte() == 1;
vr.keyPassphraseNeeded = source.readByte() == 1; vr.mKeyPassphraseNeeded = source.readByte() == 1;
vr.signatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader()); vr.mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
return vr; return vr;
} }

View File

@ -17,22 +17,10 @@
package org.sufficientlysecure.keychain.pgp; package org.sufficientlysecure.keychain.pgp;
import java.io.File; import android.content.Context;
import java.io.FileNotFoundException; import android.content.pm.PackageInfo;
import java.io.IOException; import android.content.pm.PackageManager.NameNotFoundException;
import java.io.InputStream; import org.spongycastle.openpgp.*;
import java.io.RandomAccessFile;
import java.security.SecureRandom;
import java.util.Iterator;
import java.util.regex.Pattern;
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.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@ -42,21 +30,25 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import android.content.Context; import java.io.File;
import android.content.pm.PackageInfo; import java.io.IOException;
import android.content.pm.PackageManager.NameNotFoundException; 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 class PgpHelper {
public static Pattern PGP_MESSAGE = Pattern.compile( public static final Pattern PGP_MESSAGE = Pattern.compile(
".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL); ".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*", Pattern.DOTALL);
public static Pattern PGP_SIGNED_MESSAGE = Pattern public static final Pattern PGP_SIGNED_MESSAGE = Pattern
.compile( .compile(
".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*", ".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
Pattern.DOTALL); Pattern.DOTALL);
public static Pattern PGP_PUBLIC_KEY = Pattern.compile( public static final Pattern PGP_PUBLIC_KEY = Pattern.compile(
".*?(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----).*", ".*?(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----).*",
Pattern.DOTALL); Pattern.DOTALL);
@ -140,7 +132,7 @@ public class PgpHelper {
/** /**
* Generate a random filename * Generate a random filename
* *
* @param length * @param length
* @return * @return
*/ */
@ -170,7 +162,7 @@ public class PgpHelper {
/** /**
* Go once through stream to get length of stream. The length is later used to display progress * Go once through stream to get length of stream. The length is later used to display progress
* when encrypting/decrypting * when encrypting/decrypting
* *
* @param in * @param in
* @return * @return
* @throws IOException * @throws IOException
@ -187,9 +179,9 @@ public class PgpHelper {
/** /**
* Deletes file securely by overwriting it with random data before deleting it. * Deletes file securely by overwriting it with random data before deleting it.
* * <p/>
* TODO: Does this really help on flash storage? * TODO: Does this really help on flash storage?
* *
* @param context * @param context
* @param progress * @param progress
* @param file * @param file
@ -206,8 +198,9 @@ public class PgpHelper {
int pos = 0; int pos = 0;
String msg = context.getString(R.string.progress_deleting_securely, file.getName()); String msg = context.getString(R.string.progress_deleting_securely, file.getName());
while (pos < length) { while (pos < length) {
if (progress != null) if (progress != null) {
progress.setProgress(msg, (int) (100 * pos / length), 100); progress.setProgress(msg, (int) (100 * pos / length), 100);
}
random.nextBytes(data); random.nextBytes(data);
raf.write(data); raf.write(data);
pos += data.length; pos += data.length;

View File

@ -17,20 +17,11 @@
package org.sufficientlysecure.keychain.pgp; package org.sufficientlysecure.keychain.pgp;
import java.io.ByteArrayOutputStream; import android.content.Context;
import java.io.FileNotFoundException; import android.os.Bundle;
import java.io.IOException; import android.os.Environment;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.*;
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.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
@ -39,26 +30,36 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import org.sufficientlysecure.keychain.util.HkpKeyServer; import org.sufficientlysecure.keychain.util.*;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException; import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import android.content.Context; import java.io.ByteArrayOutputStream;
import android.os.Bundle; import java.io.IOException;
import android.os.Environment; import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class PgpImportExport { public class PgpImportExport {
private Context mContext; private Context mContext;
private ProgressDialogUpdater mProgress; private ProgressDialogUpdater mProgress;
private KeychainServiceListener mKeychainServiceListener;
public PgpImportExport(Context context, ProgressDialogUpdater progress) { public PgpImportExport(Context context, ProgressDialogUpdater progress) {
super(); super();
this.mContext = context; this.mContext = context;
this.mProgress = progress; 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) { public void updateProgress(int message, int current, int total) {
if (mProgress != null) { if (mProgress != null) {
mProgress.setProgress(message, current, total); mProgress.setProgress(message, current, total);
@ -96,8 +97,8 @@ public class PgpImportExport {
return false; return false;
} finally { } finally {
try { try {
if (aos != null) aos.close(); if (aos != null) { aos.close(); }
if (bos != null) bos.close(); if (bos != null) { bos.close(); }
} catch (IOException e) { } catch (IOException e) {
} }
} }
@ -188,8 +189,10 @@ public class PgpImportExport {
if (secretKeyRing != null) { if (secretKeyRing != null) {
secretKeyRing.encode(arOutStream); secretKeyRing.encode(arOutStream);
} }
// Else if it's a public key get the PGPPublicKeyRing if (mKeychainServiceListener.hasServiceStopped()) {
// and encode that to the output arOutStream.close();
return null;
}
} else { } else {
updateProgress(i * 100 / rowIdsSize, 100); updateProgress(i * 100 / rowIdsSize, 100);
PGPPublicKeyRing publicKeyRing = PGPPublicKeyRing publicKeyRing =
@ -198,6 +201,11 @@ public class PgpImportExport {
if (publicKeyRing != null) { if (publicKeyRing != null) {
publicKeyRing.encode(arOutStream); publicKeyRing.encode(arOutStream);
} }
if (mKeychainServiceListener.hasServiceStopped()) {
arOutStream.close();
return null;
}
} }
arOutStream.close(); arOutStream.close();
@ -245,8 +253,9 @@ public class PgpImportExport {
} }
newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key); newPubRing = PGPPublicKeyRing.insertPublicKey(newPubRing, key);
} }
if (newPubRing != null) if (newPubRing != null) {
ProviderHelper.saveKeyRing(mContext, newPubRing); ProviderHelper.saveKeyRing(mContext, newPubRing);
}
// TODO: remove status returns, use exceptions! // TODO: remove status returns, use exceptions!
status = Id.return_value.ok; status = Id.return_value.ok;
} }

View File

@ -17,21 +17,9 @@
package org.sufficientlysecure.keychain.pgp; package org.sufficientlysecure.keychain.pgp;
import java.util.Calendar; import android.content.Context;
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;
import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.*;
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.spongycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@ -39,7 +27,9 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import android.content.Context; import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PgpKeyHelper { public class PgpKeyHelper {

View File

@ -17,48 +17,20 @@
package org.sufficientlysecure.keychain.pgp; package org.sufficientlysecure.keychain.pgp;
import java.io.IOException; import android.content.Context;
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.TimeZone;
import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.provider.BouncyCastleProvider; import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.jce.spec.ElGamalParameterSpec; import org.spongycastle.jce.spec.ElGamalParameterSpec;
import org.spongycastle.openpgp.PGPEncryptedData; import org.spongycastle.openpgp.*;
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.PGPUtil;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder; import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.PGPDigestCalculator; import org.spongycastle.openpgp.operator.PGPDigestCalculator;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; import org.spongycastle.openpgp.operator.jcajce.*;
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.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@ -68,21 +40,27 @@ import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Primes; import org.sufficientlysecure.keychain.util.Primes;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import android.content.Context; import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class PgpKeyOperation { public class PgpKeyOperation {
private Context mContext; private Context mContext;
private ProgressDialogUpdater mProgress; private ProgressDialogUpdater mProgress;
private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[] { private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = new int[]{
SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192, SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192,
SymmetricKeyAlgorithmTags.AES_128, SymmetricKeyAlgorithmTags.CAST5, SymmetricKeyAlgorithmTags.AES_128, SymmetricKeyAlgorithmTags.CAST5,
SymmetricKeyAlgorithmTags.TRIPLE_DES }; SymmetricKeyAlgorithmTags.TRIPLE_DES};
private static final int[] PREFERRED_HASH_ALGORITHMS = new int[] { HashAlgorithmTags.SHA1, private static final int[] PREFERRED_HASH_ALGORITHMS = new int[]{HashAlgorithmTags.SHA1,
HashAlgorithmTags.SHA256, HashAlgorithmTags.RIPEMD160 }; HashAlgorithmTags.SHA256, HashAlgorithmTags.RIPEMD160};
private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[] { private static final int[] PREFERRED_COMPRESSION_ALGORITHMS = new int[]{
CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2, CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2,
CompressionAlgorithmTags.ZIP }; CompressionAlgorithmTags.ZIP};
public PgpKeyOperation(Context context, ProgressDialogUpdater progress) { public PgpKeyOperation(Context context, ProgressDialogUpdater progress) {
super(); super();
@ -104,7 +82,7 @@ public class PgpKeyOperation {
/** /**
* Creates new secret key. * Creates new secret key.
* *
* @param algorithmChoice * @param algorithmChoice
* @param keySize * @param keySize
* @param passphrase * @param passphrase
@ -119,8 +97,9 @@ public class PgpKeyOperation {
// TODO: key flags? // TODO: key flags?
public PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase, public PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase,
boolean isMasterKey) throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, boolean isMasterKey)
PgpGeneralException, InvalidAlgorithmParameterException { throws NoSuchAlgorithmException, PGPException, NoSuchProviderException,
PgpGeneralException, InvalidAlgorithmParameterException {
if (keySize < 512) { if (keySize < 512) {
throw new PgpGeneralException(mContext.getString(R.string.error_key_size_minimum512bit)); throw new PgpGeneralException(mContext.getString(R.string.error_key_size_minimum512bit));
@ -134,41 +113,41 @@ public class PgpKeyOperation {
KeyPairGenerator keyGen = null; KeyPairGenerator keyGen = null;
switch (algorithmChoice) { switch (algorithmChoice) {
case Id.choice.algorithm.dsa: { case Id.choice.algorithm.dsa: {
keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME); keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
keyGen.initialize(keySize, new SecureRandom()); keyGen.initialize(keySize, new SecureRandom());
algorithm = PGPPublicKey.DSA; algorithm = PGPPublicKey.DSA;
break; break;
}
case Id.choice.algorithm.elgamal: {
if (isMasterKey) {
throw new PgpGeneralException(
mContext.getString(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); case Id.choice.algorithm.elgamal: {
if (isMasterKey) {
throw new PgpGeneralException(
mContext.getString(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");
keyGen.initialize(elParams); ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g);
algorithm = PGPPublicKey.ELGAMAL_ENCRYPT;
break;
}
case Id.choice.algorithm.rsa: { keyGen.initialize(elParams);
keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME); algorithm = PGPPublicKey.ELGAMAL_ENCRYPT;
keyGen.initialize(keySize, new SecureRandom()); break;
}
algorithm = PGPPublicKey.RSA_GENERAL; case Id.choice.algorithm.rsa: {
break; keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
} keyGen.initialize(keySize, new SecureRandom());
default: { algorithm = PGPPublicKey.RSA_GENERAL;
throw new PgpGeneralException( break;
mContext.getString(R.string.error_unknown_algorithm_choice)); }
}
default: {
throw new PgpGeneralException(
mContext.getString(R.string.error_unknown_algorithm_choice));
}
} }
// build new key pair // build new key pair
@ -184,13 +163,13 @@ public class PgpKeyOperation {
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
PGPSecretKey secKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(), PGPSecretKey secKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
sha1Calc, isMasterKey, keyEncryptor); sha1Calc, isMasterKey, keyEncryptor);
return secKey; return secKey;
} }
public void changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassPhrase, public void changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassPhrase,
String newPassPhrase) throws IOException, PGPException, String newPassPhrase) throws IOException, PGPException,
NoSuchProviderException { NoSuchProviderException {
updateProgress(R.string.progress_building_key, 0, 100); updateProgress(R.string.progress_building_key, 0, 100);
@ -218,9 +197,9 @@ public class PgpKeyOperation {
} }
public void buildSecretKey(ArrayList<String> userIds, ArrayList<PGPSecretKey> keys, public void buildSecretKey(ArrayList<String> userIds, ArrayList<PGPSecretKey> keys,
ArrayList<Integer> keysUsages, ArrayList<GregorianCalendar> keysExpiryDates, ArrayList<Integer> keysUsages, ArrayList<GregorianCalendar> keysExpiryDates,
long masterKeyId, String oldPassPhrase, long masterKeyId, String oldPassPhrase,
String newPassPhrase) throws PgpGeneralException, NoSuchProviderException, String newPassPhrase) throws PgpGeneralException, NoSuchProviderException,
PGPException, NoSuchAlgorithmException, SignatureException, IOException { PGPException, NoSuchAlgorithmException, SignatureException, IOException {
Log.d(Constants.TAG, "userIds: " + userIds.toString()); Log.d(Constants.TAG, "userIds: " + userIds.toString());
@ -237,8 +216,10 @@ public class PgpKeyOperation {
updateProgress(R.string.progress_preparing_master_key, 10, 100); updateProgress(R.string.progress_preparing_master_key, 10, 100);
int usageId = keysUsages.get(0); int usageId = keysUsages.get(0);
boolean canSign = (usageId == Id.choice.usage.sign_only || usageId == Id.choice.usage.sign_and_encrypt); boolean canSign =
boolean canEncrypt = (usageId == Id.choice.usage.encrypt_only || usageId == Id.choice.usage.sign_and_encrypt); (usageId == Id.choice.usage.sign_only || usageId == Id.choice.usage.sign_and_encrypt);
boolean canEncrypt =
(usageId == Id.choice.usage.encrypt_only || usageId == Id.choice.usage.sign_and_encrypt);
String mainUserId = userIds.get(0); String mainUserId = userIds.get(0);
@ -303,13 +284,17 @@ public class PgpKeyOperation {
GregorianCalendar expiryDate = keysExpiryDates.get(0); GregorianCalendar expiryDate = keysExpiryDates.get(0);
//note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c //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! //here we purposefully ignore partial days in each date - long type has no fractional part!
long numDays = (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000); long numDays =
if (numDays <= 0) (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000);
throw new PgpGeneralException(mContext.getString(R.string.error_expiry_must_come_after_creation)); if (numDays <= 0) {
throw new PgpGeneralException(
mContext.getString(R.string.error_expiry_must_come_after_creation));
}
hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400);
} else { } else {
hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding, //do this explicitly, although since we're rebuilding,
//this happens anyway hashedPacketsGen.setKeyExpirationTime(false, 0);
//this happens anyway
} }
updateProgress(R.string.progress_building_master_key, 30, 100); updateProgress(R.string.progress_building_master_key, 30, 100);
@ -352,8 +337,10 @@ public class PgpKeyOperation {
keyFlags = 0; keyFlags = 0;
usageId = keysUsages.get(i); usageId = keysUsages.get(i);
canSign = (usageId == Id.choice.usage.sign_only || usageId == Id.choice.usage.sign_and_encrypt); canSign =
canEncrypt = (usageId == Id.choice.usage.encrypt_only || usageId == Id.choice.usage.sign_and_encrypt); (usageId == Id.choice.usage.sign_only || usageId == Id.choice.usage.sign_and_encrypt);
canEncrypt =
(usageId == Id.choice.usage.encrypt_only || usageId == Id.choice.usage.sign_and_encrypt);
if (canSign) { if (canSign) {
Date todayDate = new Date(); //both sig times the same Date todayDate = new Date(); //both sig times the same
keyFlags |= KeyFlags.SIGN_DATA; keyFlags |= KeyFlags.SIGN_DATA;
@ -382,13 +369,17 @@ public class PgpKeyOperation {
GregorianCalendar expiryDate = keysExpiryDates.get(i); GregorianCalendar expiryDate = keysExpiryDates.get(i);
//note that the below, (a/c) - (b/c) is *not* the same as (a - b) /c //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! //here we purposefully ignore partial days in each date - long type has no fractional part!
long numDays = (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000); long numDays =
if (numDays <= 0) (expiryDate.getTimeInMillis() / 86400000) - (creationDate.getTimeInMillis() / 86400000);
throw new PgpGeneralException(mContext.getString(R.string.error_expiry_must_come_after_creation)); if (numDays <= 0) {
throw new PgpGeneralException
(mContext.getString(R.string.error_expiry_must_come_after_creation));
}
hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400); hashedPacketsGen.setKeyExpirationTime(false, numDays * 86400);
} else { } else {
hashedPacketsGen.setKeyExpirationTime(false, 0); //do this explicitly, although since we're rebuilding, //do this explicitly, although since we're rebuilding,
//this happens anyway hashedPacketsGen.setKeyExpirationTime(false, 0);
//this happens anyway
} }
keyGen.addSubKey(subKeyPair, hashedPacketsGen.generate(), unhashedPacketsGen.generate()); keyGen.addSubKey(subKeyPair, hashedPacketsGen.generate(), unhashedPacketsGen.generate());

View File

@ -18,28 +18,11 @@
package org.sufficientlysecure.keychain.pgp; package org.sufficientlysecure.keychain.pgp;
import android.content.Context; import android.content.Context;
import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.BCPGOutputStream; import org.spongycastle.bcpg.BCPGOutputStream;
import org.spongycastle.openpgp.PGPCompressedDataGenerator; import org.spongycastle.openpgp.*;
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.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; import org.spongycastle.openpgp.operator.jcajce.*;
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.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@ -49,11 +32,7 @@ import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import java.io.BufferedReader; import java.io.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException; import java.security.NoSuchProviderException;
import java.security.SignatureException; import java.security.SignatureException;
@ -63,110 +42,110 @@ import java.util.Date;
* This class uses a Builder pattern! * This class uses a Builder pattern!
*/ */
public class PgpSignEncrypt { public class PgpSignEncrypt {
private Context context; private Context mContext;
private InputData data; private InputData mData;
private OutputStream outStream; private OutputStream mOutStream;
private ProgressDialogUpdater progress; private ProgressDialogUpdater mProgress;
private boolean enableAsciiArmorOutput; private boolean mEnableAsciiArmorOutput;
private int compressionId; private int mCompressionId;
private long[] encryptionKeyIds; private long[] mEncryptionKeyIds;
private String encryptionPassphrase; private String mEncryptionPassphrase;
private int symmetricEncryptionAlgorithm; private int mSymmetricEncryptionAlgorithm;
private long signatureKeyId; private long mSignatureKeyId;
private int signatureHashAlgorithm; private int mSignatureHashAlgorithm;
private boolean signatureForceV3; private boolean mSignatureForceV3;
private String signaturePassphrase; private String mSignaturePassphrase;
private PgpSignEncrypt(Builder builder) { private PgpSignEncrypt(Builder builder) {
// private Constructor can only be called from Builder // private Constructor can only be called from Builder
this.context = builder.context; this.mContext = builder.mContext;
this.data = builder.data; this.mData = builder.mData;
this.outStream = builder.outStream; this.mOutStream = builder.mOutStream;
this.progress = builder.progress; this.mProgress = builder.mProgress;
this.enableAsciiArmorOutput = builder.enableAsciiArmorOutput; this.mEnableAsciiArmorOutput = builder.mEnableAsciiArmorOutput;
this.compressionId = builder.compressionId; this.mCompressionId = builder.mCompressionId;
this.encryptionKeyIds = builder.encryptionKeyIds; this.mEncryptionKeyIds = builder.mEncryptionKeyIds;
this.encryptionPassphrase = builder.encryptionPassphrase; this.mEncryptionPassphrase = builder.mEncryptionPassphrase;
this.symmetricEncryptionAlgorithm = builder.symmetricEncryptionAlgorithm; this.mSymmetricEncryptionAlgorithm = builder.mSymmetricEncryptionAlgorithm;
this.signatureKeyId = builder.signatureKeyId; this.mSignatureKeyId = builder.mSignatureKeyId;
this.signatureHashAlgorithm = builder.signatureHashAlgorithm; this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm;
this.signatureForceV3 = builder.signatureForceV3; this.mSignatureForceV3 = builder.mSignatureForceV3;
this.signaturePassphrase = builder.signaturePassphrase; this.mSignaturePassphrase = builder.mSignaturePassphrase;
} }
public static class Builder { public static class Builder {
// mandatory parameter // mandatory parameter
private Context context; private Context mContext;
private InputData data; private InputData mData;
private OutputStream outStream; private OutputStream mOutStream;
// optional // optional
private ProgressDialogUpdater progress = null; private ProgressDialogUpdater mProgress = null;
private boolean enableAsciiArmorOutput = false; private boolean mEnableAsciiArmorOutput = false;
private int compressionId = Id.choice.compression.none; private int mCompressionId = Id.choice.compression.none;
private long[] encryptionKeyIds = new long[0]; private long[] mEncryptionKeyIds = new long[0];
private String encryptionPassphrase = null; private String mEncryptionPassphrase = null;
private int symmetricEncryptionAlgorithm = 0; private int mSymmetricEncryptionAlgorithm = 0;
private long signatureKeyId = Id.key.none; private long mSignatureKeyId = Id.key.none;
private int signatureHashAlgorithm = 0; private int mSignatureHashAlgorithm = 0;
private boolean signatureForceV3 = false; private boolean mSignatureForceV3 = false;
private String signaturePassphrase = null; private String mSignaturePassphrase = null;
public Builder(Context context, InputData data, OutputStream outStream) { public Builder(Context context, InputData data, OutputStream outStream) {
this.context = context; this.mContext = context;
this.data = data; this.mData = data;
this.outStream = outStream; this.mOutStream = outStream;
} }
public Builder progress(ProgressDialogUpdater progress) { public Builder progress(ProgressDialogUpdater progress) {
this.progress = progress; this.mProgress = progress;
return this; return this;
} }
public Builder enableAsciiArmorOutput(boolean enableAsciiArmorOutput) { public Builder enableAsciiArmorOutput(boolean enableAsciiArmorOutput) {
this.enableAsciiArmorOutput = enableAsciiArmorOutput; this.mEnableAsciiArmorOutput = enableAsciiArmorOutput;
return this; return this;
} }
public Builder compressionId(int compressionId) { public Builder compressionId(int compressionId) {
this.compressionId = compressionId; this.mCompressionId = compressionId;
return this; return this;
} }
public Builder encryptionKeyIds(long[] encryptionKeyIds) { public Builder encryptionKeyIds(long[] encryptionKeyIds) {
this.encryptionKeyIds = encryptionKeyIds; this.mEncryptionKeyIds = encryptionKeyIds;
return this; return this;
} }
public Builder encryptionPassphrase(String encryptionPassphrase) { public Builder encryptionPassphrase(String encryptionPassphrase) {
this.encryptionPassphrase = encryptionPassphrase; this.mEncryptionPassphrase = encryptionPassphrase;
return this; return this;
} }
public Builder symmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) { public Builder symmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) {
this.symmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm; this.mSymmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
return this; return this;
} }
public Builder signatureKeyId(long signatureKeyId) { public Builder signatureKeyId(long signatureKeyId) {
this.signatureKeyId = signatureKeyId; this.mSignatureKeyId = signatureKeyId;
return this; return this;
} }
public Builder signatureHashAlgorithm(int signatureHashAlgorithm) { public Builder signatureHashAlgorithm(int signatureHashAlgorithm) {
this.signatureHashAlgorithm = signatureHashAlgorithm; this.mSignatureHashAlgorithm = signatureHashAlgorithm;
return this; return this;
} }
public Builder signatureForceV3(boolean signatureForceV3) { public Builder signatureForceV3(boolean signatureForceV3) {
this.signatureForceV3 = signatureForceV3; this.mSignatureForceV3 = signatureForceV3;
return this; return this;
} }
public Builder signaturePassphrase(String signaturePassphrase) { public Builder signaturePassphrase(String signaturePassphrase) {
this.signaturePassphrase = signaturePassphrase; this.mSignaturePassphrase = signaturePassphrase;
return this; return this;
} }
@ -176,14 +155,14 @@ public class PgpSignEncrypt {
} }
public void updateProgress(int message, int current, int total) { public void updateProgress(int message, int current, int total) {
if (progress != null) { if (mProgress != null) {
progress.setProgress(message, current, total); mProgress.setProgress(message, current, total);
} }
} }
public void updateProgress(int current, int total) { public void updateProgress(int current, int total) {
if (progress != null) { if (mProgress != null) {
progress.setProgress(current, total); mProgress.setProgress(current, total);
} }
} }
@ -201,17 +180,17 @@ public class PgpSignEncrypt {
throws IOException, PgpGeneralException, PGPException, NoSuchProviderException, throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
NoSuchAlgorithmException, SignatureException { NoSuchAlgorithmException, SignatureException {
boolean enableSignature = signatureKeyId != Id.key.none; boolean enableSignature = mSignatureKeyId != Id.key.none;
boolean enableEncryption = (encryptionKeyIds.length != 0 || encryptionPassphrase != null); boolean enableEncryption = (mEncryptionKeyIds.length != 0 || mEncryptionPassphrase != null);
boolean enableCompression = (enableEncryption && compressionId != Id.choice.compression.none); boolean enableCompression = (enableEncryption && mCompressionId != Id.choice.compression.none);
Log.d(Constants.TAG, "enableSignature:" + enableSignature Log.d(Constants.TAG, "enableSignature:" + enableSignature
+ "\nenableEncryption:" + enableEncryption + "\nenableEncryption:" + enableEncryption
+ "\nenableCompression:" + enableCompression + "\nenableCompression:" + enableCompression
+ "\nenableAsciiArmorOutput:" + enableAsciiArmorOutput); + "\nenableAsciiArmorOutput:" + mEnableAsciiArmorOutput);
int signatureType; int signatureType;
if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) { if (mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
// for sign-only ascii text // for sign-only ascii text
signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT; signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
} else { } else {
@ -220,12 +199,12 @@ public class PgpSignEncrypt {
ArmoredOutputStream armorOut = null; ArmoredOutputStream armorOut = null;
OutputStream out; OutputStream out;
if (enableAsciiArmorOutput) { if (mEnableAsciiArmorOutput) {
armorOut = new ArmoredOutputStream(outStream); armorOut = new ArmoredOutputStream(mOutStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(context)); armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
out = armorOut; out = armorOut;
} else { } else {
out = outStream; out = mOutStream;
} }
/* Get keys for signature generation for later usage */ /* Get keys for signature generation for later usage */
@ -233,25 +212,25 @@ public class PgpSignEncrypt {
PGPSecretKeyRing signingKeyRing = null; PGPSecretKeyRing signingKeyRing = null;
PGPPrivateKey signaturePrivateKey = null; PGPPrivateKey signaturePrivateKey = null;
if (enableSignature) { if (enableSignature) {
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId); signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, mSignatureKeyId);
signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId); signingKey = PgpKeyHelper.getSigningKey(mContext, mSignatureKeyId);
if (signingKey == null) { if (signingKey == null) {
throw new PgpGeneralException(context.getString(R.string.error_signature_failed)); throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
} }
if (signaturePassphrase == null) { if (mSignaturePassphrase == null) {
throw new PgpGeneralException( throw new PgpGeneralException(
context.getString(R.string.error_no_signature_passphrase)); mContext.getString(R.string.error_no_signature_passphrase));
} }
updateProgress(R.string.progress_extracting_signature_key, 0, 100); updateProgress(R.string.progress_extracting_signature_key, 0, 100);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray()); Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray());
signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor); signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) { if (signaturePrivateKey == null) {
throw new PgpGeneralException( throw new PgpGeneralException(
context.getString(R.string.error_could_not_extract_private_key)); mContext.getString(R.string.error_could_not_extract_private_key));
} }
} }
updateProgress(R.string.progress_preparing_streams, 5, 100); updateProgress(R.string.progress_preparing_streams, 5, 100);
@ -261,23 +240,23 @@ public class PgpSignEncrypt {
if (enableEncryption) { if (enableEncryption) {
// has Integrity packet enabled! // has Integrity packet enabled!
JcePGPDataEncryptorBuilder encryptorBuilder = JcePGPDataEncryptorBuilder encryptorBuilder =
new JcePGPDataEncryptorBuilder(symmetricEncryptionAlgorithm) new JcePGPDataEncryptorBuilder(mSymmetricEncryptionAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
.setWithIntegrityPacket(true); .setWithIntegrityPacket(true);
cPk = new PGPEncryptedDataGenerator(encryptorBuilder); cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
if (encryptionKeyIds.length == 0) { if (mEncryptionKeyIds.length == 0) {
// Symmetric encryption // Symmetric encryption
Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption"); Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator = JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
new JcePBEKeyEncryptionMethodGenerator(encryptionPassphrase.toCharArray()); new JcePBEKeyEncryptionMethodGenerator(mEncryptionPassphrase.toCharArray());
cPk.addMethod(symmetricEncryptionGenerator); cPk.addMethod(symmetricEncryptionGenerator);
} else { } else {
// Asymmetric encryption // Asymmetric encryption
for (long id : encryptionKeyIds) { for (long id : mEncryptionKeyIds) {
PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(context, id); PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(mContext, id);
if (key != null) { if (key != null) {
JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator = JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
new JcePublicKeyKeyEncryptionMethodGenerator(key); new JcePublicKeyKeyEncryptionMethodGenerator(key);
@ -295,10 +274,10 @@ public class PgpSignEncrypt {
// content signer based on signing key algorithm and chosen hash algorithm // content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
signingKey.getPublicKey().getAlgorithm(), signatureHashAlgorithm) signingKey.getPublicKey().getAlgorithm(), mSignatureHashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
if (signatureForceV3) { if (mSignatureForceV3) {
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder); signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
signatureV3Generator.init(signatureType, signaturePrivateKey); signatureV3Generator.init(signatureType, signaturePrivateKey);
} else { } else {
@ -322,14 +301,14 @@ public class PgpSignEncrypt {
encryptionOut = cPk.open(out, new byte[1 << 16]); encryptionOut = cPk.open(out, new byte[1 << 16]);
if (enableCompression) { if (enableCompression) {
compressGen = new PGPCompressedDataGenerator(compressionId); compressGen = new PGPCompressedDataGenerator(mCompressionId);
bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut)); bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
} else { } else {
bcpgOut = new BCPGOutputStream(encryptionOut); bcpgOut = new BCPGOutputStream(encryptionOut);
} }
if (enableSignature) { if (enableSignature) {
if (signatureForceV3) { if (mSignatureForceV3) {
signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut); signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
} else { } else {
signatureGenerator.generateOnePassVersion(false).encode(bcpgOut); signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
@ -345,13 +324,13 @@ public class PgpSignEncrypt {
long progress = 0; long progress = 0;
int n; int n;
byte[] buffer = new byte[1 << 16]; byte[] buffer = new byte[1 << 16];
InputStream in = data.getInputStream(); InputStream in = mData.getInputStream();
while ((n = in.read(buffer)) > 0) { while ((n = in.read(buffer)) > 0) {
pOut.write(buffer, 0, n); pOut.write(buffer, 0, n);
// update signature buffer if signature is requested // update signature buffer if signature is requested
if (enableSignature) { if (enableSignature) {
if (signatureForceV3) { if (mSignatureForceV3) {
signatureV3Generator.update(buffer, 0, n); signatureV3Generator.update(buffer, 0, n);
} else { } else {
signatureGenerator.update(buffer, 0, n); signatureGenerator.update(buffer, 0, n);
@ -359,26 +338,26 @@ public class PgpSignEncrypt {
} }
progress += n; progress += n;
if (data.getSize() != 0) { if (mData.getSize() != 0) {
updateProgress((int) (20 + (95 - 20) * progress / data.getSize()), 100); updateProgress((int) (20 + (95 - 20) * progress / mData.getSize()), 100);
} }
} }
literalGen.close(); literalGen.close();
} else if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) { } else if (mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
/* sign-only of ascii text */ /* sign-only of ascii text */
updateProgress(R.string.progress_signing, 40, 100); updateProgress(R.string.progress_signing, 40, 100);
// write directly on armor output stream // write directly on armor output stream
armorOut.beginClearText(signatureHashAlgorithm); armorOut.beginClearText(mSignatureHashAlgorithm);
InputStream in = data.getInputStream(); InputStream in = mData.getInputStream();
final BufferedReader reader = new BufferedReader(new InputStreamReader(in)); final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
final byte[] newline = "\r\n".getBytes("UTF-8"); final byte[] newline = "\r\n".getBytes("UTF-8");
if (signatureForceV3) { if (mSignatureForceV3) {
processLine(reader.readLine(), armorOut, signatureV3Generator); processLine(reader.readLine(), armorOut, signatureV3Generator);
} else { } else {
processLine(reader.readLine(), armorOut, signatureGenerator); processLine(reader.readLine(), armorOut, signatureGenerator);
@ -395,7 +374,7 @@ public class PgpSignEncrypt {
armorOut.write(newline); armorOut.write(newline);
// update signature buffer with input line // update signature buffer with input line
if (signatureForceV3) { if (mSignatureForceV3) {
signatureV3Generator.update(newline); signatureV3Generator.update(newline);
processLine(line, armorOut, signatureV3Generator); processLine(line, armorOut, signatureV3Generator);
} else { } else {
@ -415,7 +394,7 @@ public class PgpSignEncrypt {
if (enableSignature) { if (enableSignature) {
updateProgress(R.string.progress_generating_signature, 95, 100); updateProgress(R.string.progress_generating_signature, 95, 100);
if (signatureForceV3) { if (mSignatureForceV3) {
signatureV3Generator.generate().encode(pOut); signatureV3Generator.generate().encode(pOut);
} else { } else {
signatureGenerator.generate().encode(pOut); signatureGenerator.generate().encode(pOut);
@ -432,12 +411,12 @@ public class PgpSignEncrypt {
encryptionOut.close(); encryptionOut.close();
} }
if (enableAsciiArmorOutput) { if (mEnableAsciiArmorOutput) {
armorOut.close(); armorOut.close();
} }
out.close(); out.close();
outStream.close(); mOutStream.close();
updateProgress(R.string.progress_done, 100, 100); updateProgress(R.string.progress_done, 100, 100);
} }
@ -449,35 +428,36 @@ public class PgpSignEncrypt {
SignatureException { SignatureException {
OutputStream out; OutputStream out;
if (enableAsciiArmorOutput) { if (mEnableAsciiArmorOutput) {
// Ascii Armor (Radix-64) // Ascii Armor (Radix-64)
ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream); ArmoredOutputStream armorOut = new ArmoredOutputStream(mOutStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(context)); armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
out = armorOut; out = armorOut;
} else { } else {
out = outStream; out = mOutStream;
} }
if (signatureKeyId == 0) { if (mSignatureKeyId == 0) {
throw new PgpGeneralException(context.getString(R.string.error_no_signature_key)); throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
} }
PGPSecretKeyRing signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId); PGPSecretKeyRing signingKeyRing =
PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId); ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, mSignatureKeyId);
PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(mContext, mSignatureKeyId);
if (signingKey == null) { if (signingKey == null) {
throw new PgpGeneralException(context.getString(R.string.error_signature_failed)); throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
} }
if (signaturePassphrase == null) { if (mSignaturePassphrase == null) {
throw new PgpGeneralException(context.getString(R.string.error_no_signature_passphrase)); throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_passphrase));
} }
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray()); Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray());
PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor); PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) { if (signaturePrivateKey == null) {
throw new PgpGeneralException( throw new PgpGeneralException(
context.getString(R.string.error_could_not_extract_private_key)); mContext.getString(R.string.error_could_not_extract_private_key));
} }
updateProgress(R.string.progress_preparing_streams, 0, 100); updateProgress(R.string.progress_preparing_streams, 0, 100);
@ -490,12 +470,12 @@ public class PgpSignEncrypt {
// content signer based on signing key algorithm and chosen hash algorithm // content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey
.getPublicKey().getAlgorithm(), signatureHashAlgorithm) .getPublicKey().getAlgorithm(), mSignatureHashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator signatureGenerator = null; PGPSignatureGenerator signatureGenerator = null;
PGPV3SignatureGenerator signatureV3Generator = null; PGPV3SignatureGenerator signatureV3Generator = null;
if (signatureForceV3) { if (mSignatureForceV3) {
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder); signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
signatureV3Generator.init(type, signaturePrivateKey); signatureV3Generator.init(type, signaturePrivateKey);
} else { } else {
@ -510,7 +490,7 @@ public class PgpSignEncrypt {
updateProgress(R.string.progress_signing, 40, 100); updateProgress(R.string.progress_signing, 40, 100);
InputStream inStream = data.getInputStream(); InputStream inStream = mData.getInputStream();
// if (binary) { // if (binary) {
// byte[] buffer = new byte[1 << 16]; // byte[] buffer = new byte[1 << 16];
// int n = 0; // int n = 0;
@ -527,7 +507,7 @@ public class PgpSignEncrypt {
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
if (signatureForceV3) { if (mSignatureForceV3) {
processLine(line, null, signatureV3Generator); processLine(line, null, signatureV3Generator);
signatureV3Generator.update(newline); signatureV3Generator.update(newline);
} else { } else {
@ -538,13 +518,13 @@ public class PgpSignEncrypt {
// } // }
BCPGOutputStream bOut = new BCPGOutputStream(out); BCPGOutputStream bOut = new BCPGOutputStream(out);
if (signatureForceV3) { if (mSignatureForceV3) {
signatureV3Generator.generate().encode(bOut); signatureV3Generator.generate().encode(bOut);
} else { } else {
signatureGenerator.generate().encode(bOut); signatureGenerator.generate().encode(bOut);
} }
out.close(); out.close();
outStream.close(); mOutStream.close();
updateProgress(R.string.progress_done, 100, 100); updateProgress(R.string.progress_done, 100, 100);
} }

View File

@ -1,33 +1,24 @@
/*
* 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; package org.sufficientlysecure.keychain.pgp;
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;
import org.spongycastle.asn1.DERObjectIdentifier; import org.spongycastle.asn1.DERObjectIdentifier;
import org.spongycastle.asn1.x509.AuthorityKeyIdentifier; import org.spongycastle.asn1.x509.*;
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.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey; import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKey;
@ -38,30 +29,38 @@ import org.spongycastle.x509.extension.SubjectKeyIdentifierStructure;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
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;
public class PgpToX509 { public class PgpToX509 {
public final static String DN_COMMON_PART_O = "OpenPGP to X.509 Bridge"; public static final String DN_COMMON_PART_O = "OpenPGP to X.509 Bridge";
public final static String DN_COMMON_PART_OU = "OpenPGP Keychain cert"; 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 * 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 * 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 * 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. * S/MIME. A URI subjectAltName may also be set up.
* *
* @param pubKey * @param pubKey public key
* public key * @param privKey private key
* @param privKey * @param subject subject (and issuer) DN for this certificate, RFC 2253 format preferred.
* private key * @param startDate date from which the certificate will be valid (defaults to current date and time
* @param subject * if null)
* subject (and issuer) DN for this certificate, RFC 2253 format preferred. * @param endDate date until which the certificate will be valid (defaults to current date and time
* @param startDate * if null) *
* date from which the certificate will be valid (defaults to current date and time * @param subjAltNameURI URI to be placed in subjectAltName
* 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 * @return self-signed certificate
* @throws InvalidKeyException * @throws InvalidKeyException
* @throws SignatureException * @throws SignatureException
@ -70,11 +69,10 @@ public class PgpToX509 {
* @throws NoSuchProviderException * @throws NoSuchProviderException
* @throws CertificateException * @throws CertificateException
* @throws Exception * @throws Exception
*
* @author Bruno Harbulot * @author Bruno Harbulot
*/ */
public static X509Certificate createSelfSignedCert(PublicKey pubKey, PrivateKey privKey, public static X509Certificate createSelfSignedCert(PublicKey pubKey, PrivateKey privKey,
X509Name subject, Date startDate, Date endDate, String subjAltNameURI) X509Name subject, Date startDate, Date endDate, String subjAltNameURI)
throws InvalidKeyException, IllegalStateException, NoSuchAlgorithmException, throws InvalidKeyException, IllegalStateException, NoSuchAlgorithmException,
SignatureException, CertificateException, NoSuchProviderException { SignatureException, CertificateException, NoSuchProviderException {
@ -171,15 +169,12 @@ public class PgpToX509 {
/** /**
* Creates a self-signed certificate from a PGP Secret Key. * Creates a self-signed certificate from a PGP Secret Key.
* *
* @param pgpSecKey * @param pgpSecKey PGP Secret Key (from which one can extract the public and private keys and other
* PGP Secret Key (from which one can extract the public and private keys and other * attributes).
* attributes). * @param pgpPrivKey PGP Private Key corresponding to the Secret Key (password callbacks should be done
* @param pgpPrivKey * before calling this method)
* PGP Private Key corresponding to the Secret Key (password callbacks should be done * @param subjAltNameURI optional URI to embed in the subject alternative-name
* before calling this method)
* @param subjAltNameURI
* optional URI to embed in the subject alternative-name
* @return self-signed certificate * @return self-signed certificate
* @throws PGPException * @throws PGPException
* @throws NoSuchProviderException * @throws NoSuchProviderException
@ -187,11 +182,10 @@ public class PgpToX509 {
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
* @throws SignatureException * @throws SignatureException
* @throws CertificateException * @throws CertificateException
*
* @author Bruno Harbulot * @author Bruno Harbulot
*/ */
public static X509Certificate createSelfSignedCert(PGPSecretKey pgpSecKey, public static X509Certificate createSelfSignedCert(PGPSecretKey pgpSecKey,
PGPPrivateKey pgpPrivKey, String subjAltNameURI) throws PGPException, PGPPrivateKey pgpPrivKey, String subjAltNameURI) throws PGPException,
NoSuchProviderException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, NoSuchAlgorithmException,
SignatureException, CertificateException { SignatureException, CertificateException {
// get public key from secret key // get public key from secret key
@ -213,7 +207,7 @@ public class PgpToX509 {
x509NameValues.add(DN_COMMON_PART_OU); x509NameValues.add(DN_COMMON_PART_OU);
for (@SuppressWarnings("unchecked") for (@SuppressWarnings("unchecked")
Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserIDs(); it.hasNext();) { Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserIDs(); it.hasNext(); ) {
Object attrib = it.next(); Object attrib = it.next();
x509NameOids.add(X509Name.CN); x509NameOids.add(X509Name.CN);
x509NameValues.add("CryptoCall"); x509NameValues.add("CryptoCall");
@ -225,7 +219,7 @@ public class PgpToX509 {
*/ */
Log.d(Constants.TAG, "User attributes: "); Log.d(Constants.TAG, "User attributes: ");
for (@SuppressWarnings("unchecked") for (@SuppressWarnings("unchecked")
Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserAttributes(); it.hasNext();) { Iterator<Object> it = (Iterator<Object>) pgpSecKey.getUserAttributes(); it.hasNext(); ) {
Object attrib = it.next(); Object attrib = it.next();
Log.d(Constants.TAG, " - " + attrib + " -- " + attrib.getClass()); Log.d(Constants.TAG, " - " + attrib + " -- " + attrib.getClass());
} }
@ -261,14 +255,13 @@ public class PgpToX509 {
* This is a password callback handler that will fill in a password automatically. Useful to * 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 * configure passwords in advance, but should be used with caution depending on how much you
* allow passwords to be stored within your application. * allow passwords to be stored within your application.
* *
* @author Bruno Harbulot. * @author Bruno Harbulot.
*
*/ */
public final static class PredefinedPasswordCallbackHandler implements CallbackHandler { public static final class PredefinedPasswordCallbackHandler implements CallbackHandler {
private char[] password; private char[] mPassword;
private String prompt; private String mPrompt;
public PredefinedPasswordCallbackHandler(String password) { public PredefinedPasswordCallbackHandler(String password) {
this(password == null ? null : password.toCharArray(), null); this(password == null ? null : password.toCharArray(), null);
@ -283,16 +276,16 @@ public class PgpToX509 {
} }
public PredefinedPasswordCallbackHandler(char[] password, String prompt) { public PredefinedPasswordCallbackHandler(char[] password, String prompt) {
this.password = password; this.mPassword = password;
this.prompt = prompt; this.mPrompt = prompt;
} }
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback callback : callbacks) { for (Callback callback : callbacks) {
if (callback instanceof PasswordCallback) { if (callback instanceof PasswordCallback) {
PasswordCallback pwCallback = (PasswordCallback) callback; PasswordCallback pwCallback = (PasswordCallback) callback;
if ((this.prompt == null) || (this.prompt.equals(pwCallback.getPrompt()))) { if ((this.mPrompt == null) || (this.mPrompt.equals(pwCallback.getPrompt()))) {
pwCallback.setPassword(this.password); pwCallback.setPassword(this.mPassword);
} }
} else { } else {
throw new UnsupportedCallbackException(callback, "Unrecognised callback."); throw new UnsupportedCallbackException(callback, "Unrecognised callback.");

View File

@ -1,3 +1,20 @@
/*
* 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; package org.sufficientlysecure.keychain.pgp.exception;
public class NoAsymmetricEncryptionException extends Exception { public class NoAsymmetricEncryptionException extends Exception {
@ -6,4 +23,4 @@ public class NoAsymmetricEncryptionException extends Exception {
public NoAsymmetricEncryptionException() { public NoAsymmetricEncryptionException() {
super(); super();
} }
} }

View File

@ -1,3 +1,20 @@
/*
* 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; package org.sufficientlysecure.keychain.pgp.exception;
public class PgpGeneralException extends Exception { public class PgpGeneralException extends Exception {
@ -6,4 +23,4 @@ public class PgpGeneralException extends Exception {
public PgpGeneralException(String message) { public PgpGeneralException(String message) {
super(message); super(message);
} }
} }

View File

@ -17,10 +17,9 @@
package org.sufficientlysecure.keychain.provider; package org.sufficientlysecure.keychain.provider;
import org.sufficientlysecure.keychain.Constants;
import android.net.Uri; import android.net.Uri;
import android.provider.BaseColumns; import android.provider.BaseColumns;
import org.sufficientlysecure.keychain.Constants;
public class KeychainContract { public class KeychainContract {
@ -88,7 +87,6 @@ public class KeychainContract {
public static final String PATH_PUBLIC = "public"; public static final String PATH_PUBLIC = "public";
public static final String PATH_SECRET = "secret"; public static final String PATH_SECRET = "secret";
public static final String PATH_UNIFIED = "unified";
public static final String PATH_BY_MASTER_KEY_ID = "master_key_id"; public static final String PATH_BY_MASTER_KEY_ID = "master_key_id";
public static final String PATH_BY_KEY_ID = "key_id"; public static final String PATH_BY_KEY_ID = "key_id";
@ -109,14 +107,18 @@ public class KeychainContract {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_KEY_RINGS).build(); .appendPath(BASE_KEY_RINGS).build();
/** Use if multiple items get returned */ /**
* Use if multiple items get returned
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.key_ring"; public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.key_ring";
/** Use if a single item is returned */ /**
* Use if a single item is returned
*/
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.key_ring"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.key_ring";
public static Uri buildUnifiedKeyRingsUri() { public static Uri buildUnifiedKeyRingsUri() {
return CONTENT_URI.buildUpon().appendPath(PATH_UNIFIED).build(); return CONTENT_URI;
} }
public static Uri buildPublicKeyRingsUri() { public static Uri buildPublicKeyRingsUri() {
@ -180,10 +182,14 @@ public class KeychainContract {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_KEY_RINGS).build(); .appendPath(BASE_KEY_RINGS).build();
/** Use if multiple items get returned */ /**
* Use if multiple items get returned
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.key"; public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.key";
/** Use if a single item is returned */ /**
* Use if a single item is returned
*/
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.key"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.key";
public static Uri buildPublicKeysUri(String keyRingRowId) { public static Uri buildPublicKeysUri(String keyRingRowId) {
@ -219,10 +225,14 @@ public class KeychainContract {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_KEY_RINGS).build(); .appendPath(BASE_KEY_RINGS).build();
/** Use if multiple items get returned */ /**
* Use if multiple items get returned
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.user_id"; public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.user_id";
/** Use if a single item is returned */ /**
* Use if a single item is returned
*/
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.user_id"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.user_id";
public static Uri buildPublicUserIdsUri(String keyRingRowId) { public static Uri buildPublicUserIdsUri(String keyRingRowId) {
@ -258,10 +268,14 @@ public class KeychainContract {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_API_APPS).build(); .appendPath(BASE_API_APPS).build();
/** Use if multiple items get returned */ /**
* Use if multiple items get returned
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.api_apps"; public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.thialfihar.apg.api_apps";
/** Use if a single item is returned */ /**
* Use if a single item is returned
*/
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.api_apps"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.api_apps";
public static Uri buildIdUri(String rowId) { public static Uri buildIdUri(String rowId) {

View File

@ -17,6 +17,10 @@
package org.sufficientlysecure.keychain.provider; 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.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns;
@ -25,11 +29,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.CertsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.CertsColumns;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
public class KeychainDatabase extends SQLiteOpenHelper { public class KeychainDatabase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "apg.db"; private static final String DATABASE_NAME = "apg.db";
private static final int DATABASE_VERSION = 8; private static final int DATABASE_VERSION = 8;
@ -94,7 +93,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
+ CertsColumns.KEY_ID_CERTIFIER + " INTEGER, " // certifying key + CertsColumns.KEY_ID_CERTIFIER + " INTEGER, " // certifying key
+ CertsColumns.CREATION + " INTEGER, " + CertsColumns.CREATION + " INTEGER, "
+ CertsColumns.VERIFIED + " INTEGER, " + CertsColumns.VERIFIED + " INTEGER, "
+ CertsColumns.KEY_DATA+ " BLOB)"; + CertsColumns.KEY_DATA + " BLOB)";
KeychainDatabase(Context context) { KeychainDatabase(Context context) {

View File

@ -17,22 +17,6 @@
package org.sufficientlysecure.keychain.provider; package org.sufficientlysecure.keychain.provider;
import java.util.Arrays;
import java.util.HashMap;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.util.Log;
import android.content.ContentProvider; import android.content.ContentProvider;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.UriMatcher; import android.content.UriMatcher;
@ -44,6 +28,13 @@ import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri; import android.net.Uri;
import android.provider.BaseColumns; import android.provider.BaseColumns;
import android.text.TextUtils; import android.text.TextUtils;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.KeychainContract.*;
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 { public class KeychainProvider extends ContentProvider {
// public static final String ACTION_BROADCAST_DATABASE_CHANGE = Constants.PACKAGE_NAME // public static final String ACTION_BROADCAST_DATABASE_CHANGE = Constants.PACKAGE_NAME
@ -104,6 +95,15 @@ public class KeychainProvider extends ContentProvider {
String authority = KeychainContract.CONTENT_AUTHORITY; String authority = KeychainContract.CONTENT_AUTHORITY;
/**
* unified key rings
*
* <pre>
* key_rings
* </pre>
*/
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS, UNIFIED_KEY_RING);
/** /**
* public key rings * public key rings
* *
@ -237,20 +237,11 @@ public class KeychainProvider extends ContentProvider {
+ KeychainContract.PATH_BY_PACKAGE_NAME + "/*", API_APPS_BY_PACKAGE_NAME); + KeychainContract.PATH_BY_PACKAGE_NAME + "/*", API_APPS_BY_PACKAGE_NAME);
/** /**
* unified key rings
* <pre>
*
* key_rings/unified
*
*/
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+ KeychainContract.PATH_UNIFIED, UNIFIED_KEY_RING);
/** /**
* certifications * certifications
* <pre>
* *
* key_rings/unified * <pre>
* </pre>
* *
*/ */
matcher.addURI(authority, KeychainContract.BASE_CERTS, CERTS); matcher.addURI(authority, KeychainContract.BASE_CERTS, CERTS);
@ -394,7 +385,8 @@ public class KeychainProvider extends ContentProvider {
projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID); projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID);
projectionMap.put(KeyRingsColumns.KEY_RING_DATA, Tables.KEY_RINGS + "." projectionMap.put(KeyRingsColumns.KEY_RING_DATA, Tables.KEY_RINGS + "."
+ KeyRingsColumns.KEY_RING_DATA); + KeyRingsColumns.KEY_RING_DATA);
projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID); projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "."
+ KeyRingsColumns.MASTER_KEY_ID);
// TODO: deprecated master key id // TODO: deprecated master key id
//projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.KEY_ID); //projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.KEY_ID);
@ -403,6 +395,10 @@ public class KeychainProvider extends ContentProvider {
projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + UserIdsColumns.USER_ID); projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + UserIdsColumns.USER_ID);
// type attribute is special: if there is any grouping, choose secret over public type
projectionMap.put(KeyRingsColumns.TYPE,
"MAX(" + Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + ") AS " + KeyRingsColumns.TYPE);
return projectionMap; return projectionMap;
} }
@ -437,9 +433,11 @@ public class KeychainProvider extends ContentProvider {
* Builds default query for keyRings: KeyRings table is joined with UserIds and Keys * Builds default query for keyRings: KeyRings table is joined with UserIds and Keys
*/ */
private SQLiteQueryBuilder buildKeyRingQuery(SQLiteQueryBuilder qb, int match) { private SQLiteQueryBuilder buildKeyRingQuery(SQLiteQueryBuilder qb, int match) {
// public or secret keyring if (match != UNIFIED_KEY_RING) {
qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = "); // public or secret keyring
qb.appendWhereEscapeString(Integer.toString(getKeyType(match))); qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = ");
qb.appendWhereEscapeString(Integer.toString(getKeyType(match)));
}
// join keyrings with keys and userIds // join keyrings with keys and userIds
// Only get user id and key with rank 0 (main user id and main key) // Only get user id and key with rank 0 (main user id and main key)
@ -491,75 +489,26 @@ public class KeychainProvider extends ContentProvider {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
SQLiteDatabase db = mApgDatabase.getReadableDatabase(); SQLiteDatabase db = mApgDatabase.getReadableDatabase();
String groupBy = null;
int match = mUriMatcher.match(uri); int match = mUriMatcher.match(uri);
// screw that switch // all query() parameters, for good measure
if(match == UNIFIED_KEY_RING) { String groupBy = null, having = null;
// join keyrings with keys and userIds
// Only get user id and key with rank 0 (main user id and main key)
qb.setTables(Tables.KEY_RINGS + " INNER JOIN " + Tables.KEYS + " ON " + "("
+ Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.KEYS + "."
+ KeysColumns.KEY_RING_ROW_ID + " AND " + Tables.KEYS + "."
+ KeysColumns.RANK + " = '0') " + " INNER JOIN " + Tables.USER_IDS + " ON "
+ "(" + Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.USER_IDS + "."
+ UserIdsColumns.KEY_RING_ROW_ID + " AND " + Tables.USER_IDS + "."
+ UserIdsColumns.RANK + " = '0')");
{
HashMap<String, String> projectionMap = new HashMap<String, String>();
projectionMap.put(KeyRingsColumns.TYPE, "MAX(" + Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + ")");
projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS + "." + BaseColumns._ID);
projectionMap.put(KeyRingsColumns.KEY_RING_DATA, Tables.KEY_RINGS + "."
+ KeyRingsColumns.KEY_RING_DATA);
projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID);
// TODO: deprecated master key id
//projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.KEY_ID);
projectionMap.put(KeysColumns.FINGERPRINT, Tables.KEYS + "." + KeysColumns.FINGERPRINT);
projectionMap.put(KeysColumns.IS_REVOKED, Tables.KEYS + "." + KeysColumns.IS_REVOKED);
projectionMap.put(UserIdsColumns.USER_ID, Tables.USER_IDS + "." + UserIdsColumns.USER_ID);
qb.setProjectionMap(projectionMap);
}
if (TextUtils.isEmpty(sortOrder)) {
sortOrder = Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC";
}
// If no sort order is specified use the default
String orderBy;
if (TextUtils.isEmpty(sortOrder)) {
orderBy = Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " DESC";
} else {
orderBy = Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " DESC, " + sortOrder;
}
Cursor c = qb.query(db, projection, selection, selectionArgs,
Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID,
null, 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, Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID, null,
orderBy, null));
Log.d(Constants.TAG, "Cursor: " + DatabaseUtils.dumpCursorToString(c));
}
return c;
}
boolean all = false; boolean all = false;
switch (match) { switch (match) {
case UNIFIED_KEY_RING:
qb = buildKeyRingQuery(qb, match);
// GROUP BY so we don't get duplicates
groupBy = Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID;
if (TextUtils.isEmpty(sortOrder)) {
sortOrder = KeyRings.TYPE + " DESC, " +
Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC";
}
break;
case PUBLIC_KEY_RING: case PUBLIC_KEY_RING:
case SECRET_KEY_RING: case SECRET_KEY_RING:
qb = buildKeyRingQuery(qb, match); qb = buildKeyRingQuery(qb, match);
@ -740,8 +689,7 @@ public class KeychainProvider extends ContentProvider {
+ Tables.KEYS + "." + Keys.KEY_RING_ROW_ID + " = " + Tables.KEYS + "." + Keys.KEY_RING_ROW_ID + " = "
+ "signer." + UserIds.KEY_RING_ROW_ID + "signer." + UserIds.KEY_RING_ROW_ID
+ " AND " + " AND "
+ Tables.KEYS + "." + Keys.RANK + " = " + "signer." + Keys.RANK + " = 0"
+ "signer." + UserIds.RANK
+ ")"); + ")");
// groupBy = Tables.USER_IDS + "." + UserIds.RANK; // groupBy = Tables.USER_IDS + "." + UserIds.RANK;
@ -801,7 +749,7 @@ public class KeychainProvider extends ContentProvider {
orderBy = sortOrder; orderBy = sortOrder;
} }
Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null, orderBy); 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 // Tell the cursor what uri to watch, so it knows when its source data changes
c.setNotificationUri(getContext().getContentResolver(), uri); c.setNotificationUri(getContext().getContentResolver(), uri);

View File

@ -17,10 +17,9 @@
package org.sufficientlysecure.keychain.provider; package org.sufficientlysecure.keychain.provider;
import org.sufficientlysecure.keychain.Constants;
import android.net.Uri; import android.net.Uri;
import android.provider.BaseColumns; import android.provider.BaseColumns;
import org.sufficientlysecure.keychain.Constants;
public class KeychainServiceBlobContract { public class KeychainServiceBlobContract {

View File

@ -22,7 +22,6 @@ import android.content.Context;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns; import android.provider.BaseColumns;
import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.BlobsColumns; import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.BlobsColumns;
public class KeychainServiceBlobDatabase extends SQLiteOpenHelper { public class KeychainServiceBlobDatabase extends SQLiteOpenHelper {

View File

@ -18,11 +18,6 @@
package org.sufficientlysecure.keychain.provider; package org.sufficientlysecure.keychain.provider;
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 android.content.ContentProvider; import android.content.ContentProvider;
import android.content.ContentUris; import android.content.ContentUris;
import android.content.ContentValues; import android.content.ContentValues;
@ -31,7 +26,10 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.Uri; import android.net.Uri;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns; 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.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -40,7 +38,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
public class KeychainServiceBlobProvider extends ContentProvider { public class KeychainServiceBlobProvider extends ContentProvider {
private static final String STORE_PATH = Constants.path.APP_DIR + "/ApgBlobs"; private static final String STORE_PATH = Constants.Path.APP_DIR + "/ApgBlobs";
private KeychainServiceBlobDatabase mBlobDatabase = null; private KeychainServiceBlobDatabase mBlobDatabase = null;
@ -55,7 +53,9 @@ public class KeychainServiceBlobProvider extends ContentProvider {
return true; return true;
} }
/** {@inheritDoc} */ /**
* {@inheritDoc}
*/
@Override @Override
public Uri insert(Uri uri, ContentValues ignored) { public Uri insert(Uri uri, ContentValues ignored) {
// ContentValues are actually ignored, because we want to store a blob with no more // ContentValues are actually ignored, because we want to store a blob with no more
@ -74,7 +74,9 @@ public class KeychainServiceBlobProvider extends ContentProvider {
return Uri.withAppendedPath(insertedUri, password); return Uri.withAppendedPath(insertedUri, password);
} }
/** {@inheritDoc} */ /**
* {@inheritDoc}
*/
@Override @Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException, public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException,
FileNotFoundException { FileNotFoundException {
@ -91,9 +93,9 @@ public class KeychainServiceBlobProvider extends ContentProvider {
// get the data // get the data
SQLiteDatabase db = mBlobDatabase.getReadableDatabase(); SQLiteDatabase db = mBlobDatabase.getReadableDatabase();
Cursor result = db.query(KeychainServiceBlobDatabase.TABLE, new String[] { BaseColumns._ID }, Cursor result = db.query(KeychainServiceBlobDatabase.TABLE, new String[]{BaseColumns._ID},
BaseColumns._ID + " = ? and " + BlobsColumns.KEY + " = ?", BaseColumns._ID + " = ? and " + BlobsColumns.KEY + " = ?",
new String[] { id, key }, null, null, null); new String[]{id, key}, null, null, null);
if (result.getCount() == 0) { if (result.getCount() == 0) {
// either the key is wrong or no id exists // either the key is wrong or no id exists
@ -124,26 +126,34 @@ public class KeychainServiceBlobProvider extends ContentProvider {
return null; return null;
} }
/** {@inheritDoc} */ /**
* {@inheritDoc}
*/
@Override @Override
public String getType(Uri uri) { public String getType(Uri uri) {
return null; return null;
} }
/** {@inheritDoc} */ /**
* {@inheritDoc}
*/
@Override @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) { String sortOrder) {
return null; return null;
} }
/** {@inheritDoc} */ /**
* {@inheritDoc}
*/
@Override @Override
public int delete(Uri uri, String selection, String[] selectionArgs) { public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0; return 0;
} }
/** {@inheritDoc} */ /**
* {@inheritDoc}
*/
@Override @Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0; return 0;

View File

@ -17,24 +17,17 @@
package org.sufficientlysecure.keychain.provider; package org.sufficientlysecure.keychain.provider;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.SignatureException; import java.security.SignatureException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Date;
import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.UserAttributePacket; import org.spongycastle.bcpg.UserAttributePacket;
import org.spongycastle.bcpg.UserAttributeSubpacket; import org.spongycastle.bcpg.UserAttributeSubpacket;
import org.spongycastle.openpgp.PGPException; import android.content.*;
import org.spongycastle.openpgp.PGPKeyRing; import android.database.Cursor;
import org.spongycastle.openpgp.PGPPublicKey; import android.database.DatabaseUtils;
import org.spongycastle.openpgp.PGPPublicKeyRing; import android.net.Uri;
import org.spongycastle.openpgp.PGPSecretKey; import android.os.RemoteException;
import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.*;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
@ -50,15 +43,13 @@ import org.sufficientlysecure.keychain.service.remote.AppSettings;
import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import android.content.ContentProviderOperation; import java.io.ByteArrayOutputStream;
import android.content.ContentResolver; import java.io.IOException;
import android.content.ContentValues; import java.util.ArrayList;
import android.content.Context; import java.util.Date;
import android.content.OperationApplicationException; import java.util.HashMap;
import android.database.Cursor; import java.util.Map;
import android.database.DatabaseUtils;
import android.net.Uri;
import android.os.RemoteException;
public class ProviderHelper { public class ProviderHelper {
@ -124,7 +115,7 @@ public class ProviderHelper {
public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long keyId) { public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long keyId) {
PGPPublicKeyRing keyRing = getPGPPublicKeyRingByKeyId(context, keyId); PGPPublicKeyRing keyRing = getPGPPublicKeyRingByKeyId(context, keyId);
return (keyRing == null)? null : keyRing.getPublicKey(keyId); return (keyRing == null) ? null : keyRing.getPublicKey(keyId);
} }
/** /**
@ -175,7 +166,8 @@ public class ProviderHelper {
// get current _ID of key // get current _ID of key
long currentRowId = -1; long currentRowId = -1;
Cursor oldQuery = context.getContentResolver().query(deleteUri, new String[]{KeyRings._ID}, null, null, null); Cursor oldQuery = context.getContentResolver()
.query(deleteUri, new String[]{KeyRings._ID}, null, null, null);
if (oldQuery != null && oldQuery.moveToFirst()) { if (oldQuery != null && oldQuery.moveToFirst()) {
currentRowId = oldQuery.getLong(0); currentRowId = oldQuery.getLong(0);
} else { } else {
@ -191,10 +183,12 @@ public class ProviderHelper {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
// use exactly the same _ID again to replace key in-place. // 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, // 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 // because the currently loaded key would be gone from the database
if (currentRowId != -1) if (currentRowId != -1) {
values.put(KeyRings._ID, currentRowId); values.put(KeyRings._ID, currentRowId);
}
values.put(KeyRings.MASTER_KEY_ID, masterKeyId); values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded()); values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
@ -279,7 +273,8 @@ public class ProviderHelper {
// get current _ID of key // get current _ID of key
long currentRowId = -1; long currentRowId = -1;
Cursor oldQuery = context.getContentResolver().query(deleteUri, new String[]{KeyRings._ID}, null, null, null); Cursor oldQuery = context.getContentResolver()
.query(deleteUri, new String[]{KeyRings._ID}, null, null, null);
if (oldQuery != null && oldQuery.moveToFirst()) { if (oldQuery != null && oldQuery.moveToFirst()) {
currentRowId = oldQuery.getLong(0); currentRowId = oldQuery.getLong(0);
} else { } else {
@ -295,10 +290,12 @@ public class ProviderHelper {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
// use exactly the same _ID again to replace key in-place. // 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, // 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 // because the currently loaded key would be gone from the database
if (currentRowId != -1) if (currentRowId != -1) {
values.put(KeyRings._ID, currentRowId); values.put(KeyRings._ID, currentRowId);
}
values.put(KeyRings.MASTER_KEY_ID, masterKeyId); values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded()); values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
@ -335,7 +332,7 @@ public class ProviderHelper {
* Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing * Build ContentProviderOperation to add PGPPublicKey to database corresponding to a keyRing
*/ */
private static ContentProviderOperation buildPublicKeyOperations(Context context, private static ContentProviderOperation buildPublicKeyOperations(Context context,
long keyRingRowId, PGPPublicKey key, int rank) throws IOException { long keyRingRowId, PGPPublicKey key, int rank) throws IOException {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(Keys.KEY_ID, key.getKeyID()); values.put(Keys.KEY_ID, key.getKeyID());
values.put(Keys.IS_MASTER_KEY, key.isMasterKey()); values.put(Keys.IS_MASTER_KEY, key.isMasterKey());
@ -387,7 +384,7 @@ public class ProviderHelper {
* Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing * Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing
*/ */
private static ContentProviderOperation buildPublicUserIdOperations(Context context, private static ContentProviderOperation buildPublicUserIdOperations(Context context,
long keyRingRowId, String userId, int rank) { long keyRingRowId, String userId, int rank) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(UserIds.KEY_RING_ROW_ID, keyRingRowId); values.put(UserIds.KEY_RING_ROW_ID, keyRingRowId);
values.put(UserIds.USER_ID, userId); values.put(UserIds.USER_ID, userId);
@ -402,7 +399,7 @@ public class ProviderHelper {
* Build ContentProviderOperation to add PGPSecretKey to database corresponding to a keyRing * Build ContentProviderOperation to add PGPSecretKey to database corresponding to a keyRing
*/ */
private static ContentProviderOperation buildSecretKeyOperations(Context context, private static ContentProviderOperation buildSecretKeyOperations(Context context,
long keyRingRowId, PGPSecretKey key, int rank) throws IOException { long keyRingRowId, PGPSecretKey key, int rank) throws IOException {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
boolean hasPrivate = true; boolean hasPrivate = true;
@ -439,7 +436,7 @@ public class ProviderHelper {
* Build ContentProviderOperation to add SecretUserIds to database corresponding to a keyRing * Build ContentProviderOperation to add SecretUserIds to database corresponding to a keyRing
*/ */
private static ContentProviderOperation buildSecretUserIdOperations(Context context, private static ContentProviderOperation buildSecretUserIdOperations(Context context,
long keyRingRowId, String userId, int rank) { long keyRingRowId, String userId, int rank) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(UserIds.KEY_RING_ROW_ID, keyRingRowId); values.put(UserIds.KEY_RING_ROW_ID, keyRingRowId);
values.put(UserIds.USER_ID, userId); values.put(UserIds.USER_ID, userId);
@ -483,10 +480,10 @@ public class ProviderHelper {
ArrayList<Long> rowIds = new ArrayList<Long>(); ArrayList<Long> rowIds = new ArrayList<Long>();
if (cursor != null) { if (cursor != null) {
int IdCol = cursor.getColumnIndex(KeyRings._ID); int idCol = cursor.getColumnIndex(KeyRings._ID);
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
do { do {
rowIds.add(cursor.getLong(IdCol)); rowIds.add(cursor.getLong(idCol));
} while (cursor.moveToNext()); } while (cursor.moveToNext());
} }
} }
@ -566,7 +563,7 @@ public class ProviderHelper {
+ " AS sign_keys WHERE sign_keys." + Keys.KEY_RING_ROW_ID + " = " + " AS sign_keys WHERE sign_keys." + Keys.KEY_RING_ROW_ID + " = "
+ KeychainDatabase.Tables.KEY_RINGS + "." + KeyRings._ID + KeychainDatabase.Tables.KEY_RINGS + "." + KeyRings._ID
+ " AND sign_keys." + Keys.CAN_SIGN + " = '1' AND " + Keys.IS_MASTER_KEY + " AND sign_keys." + Keys.CAN_SIGN + " = '1' AND " + Keys.IS_MASTER_KEY
+ " = 1) AS sign",}; + " = 1) AS sign", };
ContentResolver cr = context.getContentResolver(); ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(queryUri, projection, null, null, null); Cursor cursor = cr.query(queryUri, projection, null, null, null);

View File

@ -17,48 +17,6 @@
package org.sufficientlysecure.keychain.service; package org.sufficientlysecure.keychain.service;
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.GregorianCalendar;
import java.util.List;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
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.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream;
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.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import android.app.IntentService; import android.app.IntentService;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -67,13 +25,32 @@ import android.os.Bundle;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import android.os.RemoteException; import android.os.RemoteException;
import org.spongycastle.openpgp.*;
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.*;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import org.sufficientlysecure.keychain.util.*;
import java.io.*;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
/** /**
* This Service contains all important long lasting operations for APG. It receives Intents with * 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 * data from the activities or other apps, queues these intents, executes them, and stops itself
* after doing them. * after doing them.
*/ */
public class KeychainIntentService extends IntentService implements ProgressDialogUpdater { public class KeychainIntentService extends IntentService
implements ProgressDialogUpdater, KeychainServiceListener {
/* extras that can be given by intent */ /* extras that can be given by intent */
public static final String EXTRA_MESSENGER = "messenger"; public static final String EXTRA_MESSENGER = "messenger";
@ -331,8 +308,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
builder.enableAsciiArmorOutput(useAsciiArmor) builder.enableAsciiArmorOutput(useAsciiArmor)
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures()) .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.signatureKeyId(secretKeyId) .signatureKeyId(secretKeyId)
.signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm()) .signatureHashAlgorithm(
.signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(
PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().generateSignature(); builder.build().generateSignature();
} else if (signOnly) { } else if (signOnly) {
@ -340,21 +319,26 @@ public class KeychainIntentService extends IntentService implements ProgressDial
builder.enableAsciiArmorOutput(useAsciiArmor) builder.enableAsciiArmorOutput(useAsciiArmor)
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures()) .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.signatureKeyId(secretKeyId) .signatureKeyId(secretKeyId)
.signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm()) .signatureHashAlgorithm(
.signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(
PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().execute(); builder.build().execute();
} else { } else {
Log.d(Constants.TAG, "encrypt..."); Log.d(Constants.TAG, "encrypt...");
builder.enableAsciiArmorOutput(useAsciiArmor) builder.enableAsciiArmorOutput(useAsciiArmor)
.compressionId(compressionId) .compressionId(compressionId)
.symmetricEncryptionAlgorithm(Preferences.getPreferences(this).getDefaultEncryptionAlgorithm()) .symmetricEncryptionAlgorithm(
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures()) .signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.encryptionKeyIds(encryptionKeyIds) .encryptionKeyIds(encryptionKeyIds)
.encryptionPassphrase(encryptionPassphrase) .encryptionPassphrase(encryptionPassphrase)
.signatureKeyId(secretKeyId) .signatureKeyId(secretKeyId)
.signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm()) .signatureHashAlgorithm(
.signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(
PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().execute(); builder.build().execute();
} }
@ -546,7 +530,8 @@ public class KeychainIntentService extends IntentService implements ProgressDial
ArrayList<PGPSecretKey> keys = PgpConversionHelper.BytesToPGPSecretKeyList(data ArrayList<PGPSecretKey> keys = PgpConversionHelper.BytesToPGPSecretKeyList(data
.getByteArray(SAVE_KEYRING_KEYS)); .getByteArray(SAVE_KEYRING_KEYS));
ArrayList<Integer> keysUsages = data.getIntegerArrayList(SAVE_KEYRING_KEYS_USAGES); ArrayList<Integer> keysUsages = data.getIntegerArrayList(SAVE_KEYRING_KEYS_USAGES);
ArrayList<GregorianCalendar> keysExpiryDates = (ArrayList<GregorianCalendar>) data.getSerializable(SAVE_KEYRING_KEYS_EXPIRY_DATES); ArrayList<GregorianCalendar> keysExpiryDates =
(ArrayList<GregorianCalendar>) data.getSerializable(SAVE_KEYRING_KEYS_EXPIRY_DATES);
long masterKeyId = data.getLong(SAVE_KEYRING_MASTER_KEY_ID); long masterKeyId = data.getLong(SAVE_KEYRING_MASTER_KEY_ID);
@ -601,7 +586,8 @@ public class KeychainIntentService extends IntentService implements ProgressDial
int keysTotal = 2; int keysTotal = 2;
int keysCreated = 0; int keysCreated = 0;
setProgress( setProgress(
getApplicationContext().getResources().getQuantityString(R.plurals.progress_generating, keysTotal), getApplicationContext().getResources().
getQuantityString(R.plurals.progress_generating, keysTotal),
keysCreated, keysCreated,
keysTotal); keysTotal);
PgpKeyOperation keyOperations = new PgpKeyOperation(this, this); PgpKeyOperation keyOperations = new PgpKeyOperation(this, this);
@ -705,17 +691,22 @@ public class KeychainIntentService extends IntentService implements ProgressDial
keyRingRowIds = ProviderHelper.getSecretKeyRingsRowIds(this); keyRingRowIds = ProviderHelper.getSecretKeyRingsRowIds(this);
} }
} else { } else {
for(long rowId : rowIds) { for (long rowId : rowIds) {
keyRingRowIds.add(rowId); keyRingRowIds.add(rowId);
} }
} }
Bundle resultData; Bundle resultData;
PgpImportExport pgpImportExport = new PgpImportExport(this, this); PgpImportExport pgpImportExport = new PgpImportExport(this, this, this);
resultData = pgpImportExport resultData = pgpImportExport
.exportKeyRings(keyRingRowIds, keyType, outStream); .exportKeyRings(keyRingRowIds, keyType, outStream);
if (mIsCanceled) {
boolean isDeleted = new File(outputFile).delete();
}
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) { } catch (Exception e) {
sendErrorToHandler(e); sendErrorToHandler(e);
@ -765,7 +756,8 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// need to have access to the bufferedInput, so we can reuse it for the possible // 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 // PGPObject chunks after the first one, e.g. files with several consecutive ASCII
// armor blocks // armor blocks
BufferedInputStream bufferedInput = new BufferedInputStream(new ByteArrayInputStream(downloadedKey)); BufferedInputStream bufferedInput =
new BufferedInputStream(new ByteArrayInputStream(downloadedKey));
try { try {
// read all available blocks... (asc files can contain many blocks with BEGIN END) // read all available blocks... (asc files can contain many blocks with BEGIN END)
@ -837,9 +829,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
private void sendErrorToHandler(Exception e) { private void sendErrorToHandler(Exception e) {
// Service was canceled. Do not send error to handler. // Service was canceled. Do not send error to handler.
if (this.mIsCanceled) if (this.mIsCanceled) {
return; return;
}
Log.e(Constants.TAG, "ApgService Exception: ", e); Log.e(Constants.TAG, "ApgService Exception: ", e);
e.printStackTrace(); e.printStackTrace();
@ -850,9 +842,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
private void sendMessageToHandler(Integer arg1, Integer arg2, Bundle data) { private void sendMessageToHandler(Integer arg1, Integer arg2, Bundle data) {
// Service was canceled. Do not send message to handler. // Service was canceled. Do not send message to handler.
if (this.mIsCanceled) if (this.mIsCanceled) {
return; return;
}
Message msg = Message.obtain(); Message msg = Message.obtain();
msg.arg1 = arg1; msg.arg1 = arg1;
if (arg2 != null) { if (arg2 != null) {
@ -903,4 +895,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public void setProgress(int progress, int max) { public void setProgress(int progress, int max) {
setProgress(null, progress, max); setProgress(null, progress, max);
} }
@Override
public boolean hasServiceStopped() {
return mIsCanceled;
}
} }

View File

@ -17,9 +17,6 @@
package org.sufficientlysecure.keychain.service; package org.sufficientlysecure.keychain.service;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.R;
import android.app.Activity; import android.app.Activity;
import android.content.DialogInterface.OnCancelListener; import android.content.DialogInterface.OnCancelListener;
import android.os.Bundle; import android.os.Bundle;
@ -28,6 +25,8 @@ import android.os.Message;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.widget.Toast; import android.widget.Toast;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
public class KeychainIntentServiceHandler extends Handler { public class KeychainIntentServiceHandler extends Handler {
@ -73,7 +72,8 @@ public class KeychainIntentServiceHandler extends Handler {
} }
public void showProgressDialog(FragmentActivity activity) { public void showProgressDialog(FragmentActivity activity) {
// TODO: This is a hack!, see http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult // TODO: This is a hack!, see
// http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult
final FragmentManager manager = activity.getSupportFragmentManager(); final FragmentManager manager = activity.getSupportFragmentManager();
Handler handler = new Handler(); Handler handler = new Handler();
handler.post(new Runnable() { handler.post(new Runnable() {

View File

@ -17,10 +17,15 @@
package org.sufficientlysecure.keychain.service; package org.sufficientlysecure.keychain.service;
import java.util.Date; import android.app.AlarmManager;
import java.util.HashMap; import android.app.PendingIntent;
import java.util.Iterator; import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.*;
import android.util.Log;
import android.util.LongSparseArray; import android.util.LongSparseArray;
import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey; import org.spongycastle.openpgp.PGPPrivateKey;
@ -34,28 +39,13 @@ import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import android.app.AlarmManager; import java.util.Date;
import android.app.PendingIntent; import java.util.Iterator;
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.util.Log;
/** /**
* This service runs in its own process, but is available to all other processes as the main * 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 * passphrase cache. Use the static methods addCachedPassphrase and getCachedPassphrase for
* convenience. * convenience.
*
*/ */
public class PassphraseCacheService extends Service { public class PassphraseCacheService extends Service {
public static final String TAG = Constants.TAG + ": PassphraseCacheService"; public static final String TAG = Constants.TAG + ": PassphraseCacheService";
@ -86,7 +76,7 @@ public class PassphraseCacheService extends Service {
* This caches a new passphrase in memory by sending a new command to the service. An android * 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 * 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. * new events to the alarm manager for new passphrases to let them timeout in the future.
* *
* @param context * @param context
* @param keyId * @param keyId
* @param passphrase * @param passphrase
@ -106,7 +96,7 @@ public class PassphraseCacheService extends Service {
/** /**
* Gets a cached passphrase from memory by sending an intent to the service. This method is * 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. * designed to wait until the service returns the passphrase.
* *
* @param context * @param context
* @param keyId * @param keyId
* @return passphrase or null (if no passphrase is cached for this keyId) * @return passphrase or null (if no passphrase is cached for this keyId)
@ -161,7 +151,7 @@ public class PassphraseCacheService extends Service {
/** /**
* Internal implementation to get cached passphrase. * Internal implementation to get cached passphrase.
* *
* @param keyId * @param keyId
* @return * @return
*/ */
@ -205,7 +195,7 @@ public class PassphraseCacheService extends Service {
/** /**
* Checks if key has a passphrase. * Checks if key has a passphrase.
* *
* @param secretKeyId * @param secretKeyId
* @return true if it has a passphrase * @return true if it has a passphrase
*/ */
@ -216,17 +206,17 @@ public class PassphraseCacheService extends Service {
.getPGPSecretKeyRingByKeyId(context, secretKeyId); .getPGPSecretKeyRingByKeyId(context, secretKeyId);
PGPSecretKey secretKey = null; PGPSecretKey secretKey = null;
boolean foundValidKey = false; boolean foundValidKey = false;
for (Iterator keys = secRing.getSecretKeys(); keys.hasNext();) { for (Iterator keys = secRing.getSecretKeys(); keys.hasNext(); ) {
secretKey = (PGPSecretKey)keys.next(); secretKey = (PGPSecretKey) keys.next();
if (!secretKey.isPrivateKeyEmpty()) { if (!secretKey.isPrivateKeyEmpty()) {
foundValidKey = true; foundValidKey = true;
break; break;
} }
} }
if (!foundValidKey) if (!foundValidKey) {
return false; return false;
}
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
"SC").build("".toCharArray()); "SC").build("".toCharArray());
PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor); PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor);
@ -269,7 +259,7 @@ public class PassphraseCacheService extends Service {
/** /**
* Build pending intent that is executed by alarm manager to time out a specific passphrase * Build pending intent that is executed by alarm manager to time out a specific passphrase
* *
* @param context * @param context
* @param keyId * @param keyId
* @return * @return
@ -337,7 +327,7 @@ public class PassphraseCacheService extends Service {
/** /**
* Called when one specific passphrase for keyId timed out * Called when one specific passphrase for keyId timed out
* *
* @param context * @param context
* @param keyId * @param keyId
*/ */

View File

@ -22,12 +22,12 @@ import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
public class AppSettings { public class AppSettings {
private String packageName; private String mPackageName;
private byte[] packageSignature; private byte[] mPackageSignature;
private long keyId = Id.key.none; private long mKeyId = Id.key.none;
private int encryptionAlgorithm; private int mEncryptionAlgorithm;
private int hashAlgorithm; private int mHashAlgorithm;
private int compression; private int mCompression;
public AppSettings() { public AppSettings() {
@ -35,60 +35,60 @@ public class AppSettings {
public AppSettings(String packageName, byte[] packageSignature) { public AppSettings(String packageName, byte[] packageSignature) {
super(); super();
this.packageName = packageName; this.mPackageName = packageName;
this.packageSignature = packageSignature; this.mPackageSignature = packageSignature;
// defaults: // defaults:
this.encryptionAlgorithm = PGPEncryptedData.AES_256; this.mEncryptionAlgorithm = PGPEncryptedData.AES_256;
this.hashAlgorithm = HashAlgorithmTags.SHA512; this.mHashAlgorithm = HashAlgorithmTags.SHA512;
this.compression = Id.choice.compression.zlib; this.mCompression = Id.choice.compression.zlib;
} }
public String getPackageName() { public String getPackageName() {
return packageName; return mPackageName;
} }
public void setPackageName(String packageName) { public void setPackageName(String packageName) {
this.packageName = packageName; this.mPackageName = packageName;
} }
public byte[] getPackageSignature() { public byte[] getPackageSignature() {
return packageSignature; return mPackageSignature;
} }
public void setPackageSignature(byte[] packageSignature) { public void setPackageSignature(byte[] packageSignature) {
this.packageSignature = packageSignature; this.mPackageSignature = packageSignature;
} }
public long getKeyId() { public long getKeyId() {
return keyId; return mKeyId;
} }
public void setKeyId(long scretKeyId) { public void setKeyId(long scretKeyId) {
this.keyId = scretKeyId; this.mKeyId = scretKeyId;
} }
public int getEncryptionAlgorithm() { public int getEncryptionAlgorithm() {
return encryptionAlgorithm; return mEncryptionAlgorithm;
} }
public void setEncryptionAlgorithm(int encryptionAlgorithm) { public void setEncryptionAlgorithm(int encryptionAlgorithm) {
this.encryptionAlgorithm = encryptionAlgorithm; this.mEncryptionAlgorithm = encryptionAlgorithm;
} }
public int getHashAlgorithm() { public int getHashAlgorithm() {
return hashAlgorithm; return mHashAlgorithm;
} }
public void setHashAlgorithm(int hashAlgorithm) { public void setHashAlgorithm(int hashAlgorithm) {
this.hashAlgorithm = hashAlgorithm; this.mHashAlgorithm = hashAlgorithm;
} }
public int getCompression() { public int getCompression() {
return compression; return mCompression;
} }
public void setCompression(int compression) { public void setCompression(int compression) {
this.compression = compression; this.mCompression = compression;
} }
} }

View File

@ -17,12 +17,6 @@
package org.sufficientlysecure.keychain.service.remote; package org.sufficientlysecure.keychain.service.remote;
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.util.Log;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -30,6 +24,11 @@ import android.support.v7.app.ActionBarActivity;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; 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.util.Log;
public class AppSettingsActivity extends ActionBarActivity { public class AppSettingsActivity extends ActionBarActivity {
private Uri mAppUri; private Uri mAppUri;
@ -41,7 +40,8 @@ public class AppSettingsActivity extends ActionBarActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// Inflate a "Done" custom action bar // Inflate a "Done" custom action bar
ActionBarHelper.setOneButtonView(getSupportActionBar(), R.string.api_settings_save, R.drawable.ic_action_done, ActionBarHelper.setOneButtonView(getSupportActionBar(),
R.string.api_settings_save, R.drawable.ic_action_done,
new View.OnClickListener() { new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -77,12 +77,12 @@ public class AppSettingsActivity extends ActionBarActivity {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_api_settings_revoke: case R.id.menu_api_settings_revoke:
revokeAccess(); revokeAccess();
return true; return true;
case R.id.menu_api_settings_cancel: case R.id.menu_api_settings_cancel:
finish(); finish();
return true; return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }

View File

@ -17,17 +17,6 @@
package org.sufficientlysecure.keychain.service.remote; package org.sufficientlysecure.keychain.service.remote;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.spongycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment;
import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter;
import org.sufficientlysecure.keychain.util.AlgorithmNames;
import org.sufficientlysecure.keychain.util.Log;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
@ -40,20 +29,25 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.AlphaAnimation; import android.view.animation.AlphaAnimation;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.widget.AdapterView; import android.widget.*;
import android.widget.AdapterView.OnItemSelectedListener; import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import org.spongycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment;
import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter;
import org.sufficientlysecure.keychain.util.AlgorithmNames;
import org.sufficientlysecure.keychain.util.Log;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class AppSettingsFragment extends Fragment implements public class AppSettingsFragment extends Fragment implements
SelectSecretKeyLayoutFragment.SelectSecretKeyCallback { SelectSecretKeyLayoutFragment.SelectSecretKeyCallback {
// model // model
private AppSettings appSettings; private AppSettings mAppSettings;
// view // view
private LinearLayout mAdvancedSettingsContainer; private LinearLayout mAdvancedSettingsContainer;
@ -68,16 +62,16 @@ public class AppSettingsFragment extends Fragment implements
private SelectSecretKeyLayoutFragment mSelectKeyFragment; private SelectSecretKeyLayoutFragment mSelectKeyFragment;
KeyValueSpinnerAdapter encryptionAdapter; KeyValueSpinnerAdapter mEncryptionAdapter;
KeyValueSpinnerAdapter hashAdapter; KeyValueSpinnerAdapter mHashAdapter;
KeyValueSpinnerAdapter compressionAdapter; KeyValueSpinnerAdapter mCompressionAdapter;
public AppSettings getAppSettings() { public AppSettings getAppSettings() {
return appSettings; return mAppSettings;
} }
public void setAppSettings(AppSettings appSettings) { public void setAppSettings(AppSettings appSettings) {
this.appSettings = appSettings; this.mAppSettings = appSettings;
setPackage(appSettings.getPackageName()); setPackage(appSettings.getPackageName());
mPackageName.setText(appSettings.getPackageName()); mPackageName.setText(appSettings.getPackageName());
@ -93,10 +87,10 @@ public class AppSettingsFragment extends Fragment implements
} }
mSelectKeyFragment.selectKey(appSettings.getKeyId()); mSelectKeyFragment.selectKey(appSettings.getKeyId());
mEncryptionAlgorithm.setSelection(encryptionAdapter.getPosition(appSettings mEncryptionAlgorithm.setSelection(mEncryptionAdapter.getPosition(appSettings
.getEncryptionAlgorithm())); .getEncryptionAlgorithm()));
mHashAlgorithm.setSelection(hashAdapter.getPosition(appSettings.getHashAlgorithm())); mHashAlgorithm.setSelection(mHashAdapter.getPosition(appSettings.getHashAlgorithm()));
mCompression.setSelection(compressionAdapter.getPosition(appSettings.getCompression())); mCompression.setSelection(mCompressionAdapter.getPosition(appSettings.getCompression()));
} }
/** /**
@ -139,14 +133,14 @@ public class AppSettingsFragment extends Fragment implements
AlgorithmNames algorithmNames = new AlgorithmNames(getActivity()); AlgorithmNames algorithmNames = new AlgorithmNames(getActivity());
encryptionAdapter = new KeyValueSpinnerAdapter(getActivity(), mEncryptionAdapter = new KeyValueSpinnerAdapter(getActivity(),
algorithmNames.getEncryptionNames()); algorithmNames.getEncryptionNames());
mEncryptionAlgorithm.setAdapter(encryptionAdapter); mEncryptionAlgorithm.setAdapter(mEncryptionAdapter);
mEncryptionAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() { mEncryptionAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override @Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
appSettings.setEncryptionAlgorithm((int) id); mAppSettings.setEncryptionAlgorithm((int) id);
} }
@Override @Override
@ -154,13 +148,13 @@ public class AppSettingsFragment extends Fragment implements
} }
}); });
hashAdapter = new KeyValueSpinnerAdapter(getActivity(), algorithmNames.getHashNames()); mHashAdapter = new KeyValueSpinnerAdapter(getActivity(), algorithmNames.getHashNames());
mHashAlgorithm.setAdapter(hashAdapter); mHashAlgorithm.setAdapter(mHashAdapter);
mHashAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() { mHashAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override @Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
appSettings.setHashAlgorithm((int) id); mAppSettings.setHashAlgorithm((int) id);
} }
@Override @Override
@ -168,14 +162,14 @@ public class AppSettingsFragment extends Fragment implements
} }
}); });
compressionAdapter = new KeyValueSpinnerAdapter(getActivity(), mCompressionAdapter = new KeyValueSpinnerAdapter(getActivity(),
algorithmNames.getCompressionNames()); algorithmNames.getCompressionNames());
mCompression.setAdapter(compressionAdapter); mCompression.setAdapter(mCompressionAdapter);
mCompression.setOnItemSelectedListener(new OnItemSelectedListener() { mCompression.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override @Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
appSettings.setCompression((int) id); mAppSettings.setCompression((int) id);
} }
@Override @Override
@ -237,7 +231,7 @@ public class AppSettingsFragment extends Fragment implements
*/ */
@Override @Override
public void onKeySelected(long secretKeyId) { public void onKeySelected(long secretKeyId) {
appSettings.setKeyId(secretKeyId); mAppSettings.setKeyId(secretKeyId);
} }
} }

View File

@ -23,7 +23,6 @@ import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.IBinder; import android.os.IBinder;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import org.openintents.openpgp.IOpenPgpService; import org.openintents.openpgp.IOpenPgpService;
import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.OpenPgpSignatureResult;
@ -100,7 +99,8 @@ public class OpenPgpService extends RemoteService {
intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds); intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds);
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0); PendingIntent pi = PendingIntent.getActivity
(getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0);
// return PendingIntent to be executed by client // return PendingIntent to be executed by client
Intent result = new Intent(); Intent result = new Intent();
@ -126,7 +126,8 @@ public class OpenPgpService extends RemoteService {
intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId); intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId);
// pass params through to activity that it can be returned again later to repeat pgp operation // pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0); PendingIntent pi = PendingIntent.getActivity
(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0);
// return PendingIntent to be executed by client // return PendingIntent to be executed by client
Intent result = new Intent(); Intent result = new Intent();
@ -208,7 +209,8 @@ public class OpenPgpService extends RemoteService {
} else { } else {
Intent result = new Intent(); Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_ERROR, result.putExtra(OpenPgpApi.RESULT_ERROR,
new OpenPgpError(OpenPgpError.GENERIC_ERROR, "Missing parameter user_ids or key_ids!")); new OpenPgpError(OpenPgpError.GENERIC_ERROR,
"Missing parameter user_ids or key_ids!"));
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result; return result;
} }
@ -289,7 +291,8 @@ public class OpenPgpService extends RemoteService {
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os); PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
builder.assumeSymmetric(false) // no support for symmetric encryption builder.assumeSymmetric(false) // no support for symmetric encryption
.enforcedKeyId(appSettings.getKeyId()) // allow only the private key for this app for decryption // allow only the private key for this app for decryption
.enforcedKeyId(appSettings.getKeyId())
.passphrase(passphrase); .passphrase(passphrase);
// TODO: currently does not support binary signed-only content // TODO: currently does not support binary signed-only content
@ -403,7 +406,8 @@ public class OpenPgpService extends RemoteService {
// version code is required and needs to correspond to version code of service! // version code is required and needs to correspond to version code of service!
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) { if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) {
Intent result = new Intent(); Intent result = new Intent();
OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!"); OpenPgpError error = new OpenPgpError
(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!");
result.putExtra(OpenPgpApi.RESULT_ERROR, error); result.putExtra(OpenPgpApi.RESULT_ERROR, error);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result; return result;

View File

@ -17,9 +17,6 @@
package org.sufficientlysecure.keychain.service.remote; package org.sufficientlysecure.keychain.service.remote;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@ -31,17 +28,19 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
public class RegisteredAppsAdapter extends CursorAdapter { public class RegisteredAppsAdapter extends CursorAdapter {
private LayoutInflater mInflater; private LayoutInflater mInflater;
private PackageManager pm; private PackageManager mPM;
public RegisteredAppsAdapter(Context context, Cursor c, int flags) { public RegisteredAppsAdapter(Context context, Cursor c, int flags) {
super(context, c, flags); super(context, c, flags);
mInflater = LayoutInflater.from(context); mInflater = LayoutInflater.from(context);
pm = context.getApplicationContext().getPackageManager(); mPM = context.getApplicationContext().getPackageManager();
} }
@Override @Override
@ -53,10 +52,10 @@ public class RegisteredAppsAdapter extends CursorAdapter {
if (packageName != null) { if (packageName != null) {
// get application name // get application name
try { try {
ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); ApplicationInfo ai = mPM.getApplicationInfo(packageName, 0);
text.setText(pm.getApplicationLabel(ai)); text.setText(mPM.getApplicationLabel(ai));
icon.setImageDrawable(pm.getApplicationIcon(ai)); icon.setImageDrawable(mPM.getApplicationIcon(ai));
} catch (final NameNotFoundException e) { } catch (final NameNotFoundException e) {
// fallback // fallback
text.setText(packageName); text.setText(packageName);

View File

@ -17,11 +17,10 @@
package org.sufficientlysecure.keychain.service.remote; package org.sufficientlysecure.keychain.service.remote;
import android.os.Bundle;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.DrawerActivity; import org.sufficientlysecure.keychain.ui.DrawerActivity;
import android.os.Bundle;
public class RegisteredAppsListActivity extends DrawerActivity { public class RegisteredAppsListActivity extends DrawerActivity {
@Override @Override

View File

@ -17,10 +17,6 @@
package org.sufficientlysecure.keychain.service.remote; package org.sufficientlysecure.keychain.service.remote;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
import android.content.ContentUris; import android.content.ContentUris;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
@ -33,6 +29,9 @@ import android.support.v4.content.Loader;
import android.view.View; import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
public class RegisteredAppsListFragment extends ListFragment implements public class RegisteredAppsListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor> { LoaderManager.LoaderCallbacks<Cursor> {
@ -71,7 +70,7 @@ public class RegisteredAppsListFragment extends ListFragment implements
} }
// These are the Contacts rows that we will retrieve. // These are the Contacts rows that we will retrieve.
static final String[] PROJECTION = new String[] { ApiApps._ID, ApiApps.PACKAGE_NAME }; static final String[] PROJECTION = new String[]{ApiApps._ID, ApiApps.PACKAGE_NAME};
public Loader<Cursor> onCreateLoader(int id, Bundle args) { public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This // This is called when a new Loader needs to be created. This
@ -99,4 +98,4 @@ public class RegisteredAppsListFragment extends ListFragment implements
mAdapter.swapCursor(null); mAdapter.swapCursor(null);
} }
} }

View File

@ -17,17 +17,6 @@
package org.sufficientlysecure.keychain.service.remote; package org.sufficientlysecure.keychain.service.remote;
import java.util.ArrayList;
import java.util.Arrays;
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.util.Log;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.Context; import android.content.Context;
@ -38,6 +27,16 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature; import android.content.pm.Signature;
import android.net.Uri; import android.net.Uri;
import android.os.Binder; 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.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
/** /**
* Abstract service class for remote APIs that handle app registration and user input. * Abstract service class for remote APIs that handle app registration and user input.
@ -84,7 +83,8 @@ public abstract class RemoteService extends Service {
intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature); intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature);
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_REGISTER, intent, 0); PendingIntent pi = PendingIntent.getActivity(getBaseContext(),
PRIVATE_REQUEST_CODE_REGISTER, intent, 0);
// return PendingIntent to be executed by client // return PendingIntent to be executed by client
Intent result = new Intent(); Intent result = new Intent();
@ -98,10 +98,12 @@ public abstract class RemoteService extends Service {
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE); intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE);
intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, getString(R.string.api_error_wrong_signature)); intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE,
getString(R.string.api_error_wrong_signature));
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_ERROR, intent, 0); PendingIntent pi = PendingIntent.getActivity(getBaseContext(),
PRIVATE_REQUEST_CODE_ERROR, intent, 0);
// return PendingIntent to be executed by client // return PendingIntent to be executed by client
Intent result = new Intent(); Intent result = new Intent();
@ -138,8 +140,9 @@ public abstract class RemoteService extends Service {
AppSettings settings = ProviderHelper.getApiAppSettings(this, uri); AppSettings settings = ProviderHelper.getApiAppSettings(this, uri);
if (settings != null) if (settings != null) {
return settings; return settings;
}
} }
return null; return null;
@ -213,7 +216,7 @@ public abstract class RemoteService extends Service {
return true; return true;
} else { } else {
throw new WrongPackageSignatureException( throw new WrongPackageSignatureException(
"PACKAGE NOT ALLOWED! Signature wrong! (Signature not equals signature from database)"); "PACKAGE NOT ALLOWED! Signature wrong! (Signature not equals signature from database)");
} }
} }

View File

@ -24,7 +24,6 @@ import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.view.View; import android.view.View;
import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.htmltextview.HtmlTextView; import org.sufficientlysecure.htmltextview.HtmlTextView;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
@ -88,7 +87,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE); final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE);
// Inflate a "Done"/"Cancel" custom action bar view // Inflate a "Done"/"Cancel" custom action bar view
ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.api_register_allow, R.drawable.ic_action_done, ActionBarHelper.setTwoButtonView(getSupportActionBar(),
R.string.api_register_allow, R.drawable.ic_action_done,
new View.OnClickListener() { new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -108,13 +108,14 @@ public class RemoteServiceActivity extends ActionBarActivity {
RemoteServiceActivity.this.finish(); RemoteServiceActivity.this.finish();
} }
} }
}, R.string.api_register_disallow, R.drawable.ic_action_cancel, new View.OnClickListener() { }, R.string.api_register_disallow, R.drawable.ic_action_cancel,
@Override new View.OnClickListener() {
public void onClick(View v) { @Override
// Disallow public void onClick(View v) {
RemoteServiceActivity.this.setResult(RESULT_CANCELED); // Disallow
RemoteServiceActivity.this.finish(); RemoteServiceActivity.this.setResult(RESULT_CANCELED);
} RemoteServiceActivity.this.finish();
}
} }
); );
@ -161,7 +162,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
} }
// Inflate a "Done"/"Cancel" custom action bar view // Inflate a "Done"/"Cancel" custom action bar view
ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, ActionBarHelper.setTwoButtonView(getSupportActionBar(),
R.string.btn_okay, R.drawable.ic_action_done,
new View.OnClickListener() { new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -214,7 +216,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
String text = "<font color=\"red\">" + errorMessage + "</font>"; String text = "<font color=\"red\">" + errorMessage + "</font>";
// Inflate a "Done" custom action bar view // Inflate a "Done" custom action bar view
ActionBarHelper.setOneButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, ActionBarHelper.setOneButtonView(getSupportActionBar(),
R.string.btn_okay, R.drawable.ic_action_done,
new View.OnClickListener() { new View.OnClickListener() {
@Override @Override

View File

@ -1,3 +1,20 @@
/*
* 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.service.remote; package org.sufficientlysecure.keychain.service.remote;
public class WrongPackageSignatureException extends Exception { public class WrongPackageSignatureException extends Exception {
@ -7,4 +24,4 @@ public class WrongPackageSignatureException extends Exception {
public WrongPackageSignatureException(String message) { public WrongPackageSignatureException(String message) {
super(message); super(message);
} }
} }

View File

@ -17,8 +17,20 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.util.Iterator; 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.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.*;
import android.widget.CompoundButton.OnCheckedChangeListener;
import com.beardedhen.androidbootstrap.BootstrapButton;
import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignature;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
@ -33,25 +45,7 @@ import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import android.app.ProgressDialog; import java.util.Iterator;
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.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.Spinner;
import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton;
/** /**
* Signs the specified public key with the specified secret master key * Signs the specified public key with the specified secret master key
@ -87,7 +81,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
mSelectKeyserverSpinner = (Spinner) findViewById(R.id.sign_key_keyserver); mSelectKeyserverSpinner = (Spinner) findViewById(R.id.sign_key_keyserver);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, Preferences.getPreferences(this) android.R.layout.simple_spinner_item, Preferences.getPreferences(this)
.getKeyServers()); .getKeyServers());
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSelectKeyserverSpinner.setAdapter(adapter); mSelectKeyserverSpinner.setAdapter(adapter);

View File

@ -17,37 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.regex.Matcher;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.openpgp.PGPPublicKeyRing;
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.ActionBarHelper;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
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.dialog.DeleteFileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Intent; import android.content.Intent;
@ -59,16 +28,34 @@ import android.os.Messenger;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.animation.AnimationUtils; import android.view.animation.AnimationUtils;
import android.widget.CheckBox; import android.widget.*;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import com.devspark.appmsg.AppMsg; import com.devspark.appmsg.AppMsg;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.openpgp.PGPPublicKeyRing;
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.ActionBarHelper;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
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.dialog.DeleteFileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import java.io.*;
import java.util.regex.Matcher;
@SuppressLint("NewApi") @SuppressLint("NewApi")
public class DecryptActivity extends DrawerActivity { public class DecryptActivity extends DrawerActivity {
@ -364,7 +351,7 @@ public class DecryptActivity extends DrawerActivity {
} }
} else { } else {
Log.e(Constants.TAG, Log.e(Constants.TAG,
"Direct binary data without actual file in filesystem is not supported. Please use the Remote Service API!"); "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) Toast.makeText(this, R.string.error_only_files_are_supported, Toast.LENGTH_LONG)
.show(); .show();
// end activity // end activity
@ -383,7 +370,7 @@ public class DecryptActivity extends DrawerActivity {
if (filename.endsWith(".asc") || filename.endsWith(".gpg") || filename.endsWith(".pgp")) { if (filename.endsWith(".asc") || filename.endsWith(".gpg") || filename.endsWith(".pgp")) {
filename = filename.substring(0, filename.length() - 4); filename = filename.substring(0, filename.length() - 4);
} }
mOutputFilename = Constants.path.APP_DIR + "/" + filename; mOutputFilename = Constants.Path.APP_DIR + "/" + filename;
} }
private void updateSource() { private void updateSource() {
@ -532,8 +519,11 @@ public class DecryptActivity extends DrawerActivity {
AppMsg.STYLE_ALERT).show(); AppMsg.STYLE_ALERT).show();
} finally { } finally {
try { try {
if (inStream != null) inStream.close(); if (inStream != null) {
} catch (Exception e){ } inStream.close();
}
} catch (Exception e) {
}
} }
} else { } else {
inStream = new ByteArrayInputStream(mMessage.getText().toString().getBytes()); inStream = new ByteArrayInputStream(mMessage.getText().toString().getBytes());

View File

@ -17,10 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity;
import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -30,17 +26,14 @@ import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat; import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater; import android.view.*;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import com.beardedhen.androidbootstrap.FontAwesomeText; import com.beardedhen.androidbootstrap.FontAwesomeText;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity;
public class DrawerActivity extends ActionBarActivity { public class DrawerActivity extends ActionBarActivity {
private DrawerLayout mDrawerLayout; private DrawerLayout mDrawerLayout;
@ -50,9 +43,9 @@ public class DrawerActivity extends ActionBarActivity {
private CharSequence mDrawerTitle; private CharSequence mDrawerTitle;
private CharSequence mTitle; private CharSequence mTitle;
private static Class[] mItemsClass = new Class[] { KeyListActivity.class, private static Class[] mItemsClass = new Class[]{KeyListActivity.class,
EncryptActivity.class, DecryptActivity.class, ImportKeysActivity.class, EncryptActivity.class, DecryptActivity.class, ImportKeysActivity.class,
RegisteredAppsListActivity.class }; RegisteredAppsListActivity.class};
private Class mSelectedItem; private Class mSelectedItem;
private static final int MENU_ID_PREFERENCE = 222; private static final int MENU_ID_PREFERENCE = 222;
@ -67,12 +60,12 @@ public class DrawerActivity extends ActionBarActivity {
// opens // opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
NavItem mItemIconTexts[] = new NavItem[] { NavItem mItemIconTexts[] = new NavItem[]{
new NavItem("fa-user", getString(R.string.nav_contacts)), new NavItem("fa-user", getString(R.string.nav_contacts)),
new NavItem("fa-lock", getString(R.string.nav_encrypt)), new NavItem("fa-lock", getString(R.string.nav_encrypt)),
new NavItem("fa-unlock", getString(R.string.nav_decrypt)), new NavItem("fa-unlock", getString(R.string.nav_decrypt)),
new NavItem("fa-download", getString(R.string.nav_import)), new NavItem("fa-download", getString(R.string.nav_import)),
new NavItem("fa-android", getString(R.string.nav_apps)) }; new NavItem("fa-android", getString(R.string.nav_apps))};
mDrawerList.setAdapter(new NavigationDrawerAdapter(this, R.layout.drawer_list_item, mDrawerList.setAdapter(new NavigationDrawerAdapter(this, R.layout.drawer_list_item,
mItemIconTexts)); mItemIconTexts));
@ -86,10 +79,10 @@ public class DrawerActivity extends ActionBarActivity {
// ActionBarDrawerToggle ties together the the proper interactions // ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon // between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */ mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */
mDrawerLayout, /* DrawerLayout object */ mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */ R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
R.string.drawer_open, /* "open drawer" description for accessibility */ R.string.drawer_open, /* "open drawer" description for accessibility */
R.string.drawer_close /* "close drawer" description for accessibility */ R.string.drawer_close /* "close drawer" description for accessibility */
) { ) {
public void onDrawerClosed(View view) { public void onDrawerClosed(View view) {
getSupportActionBar().setTitle(mTitle); getSupportActionBar().setTitle(mTitle);
@ -97,7 +90,7 @@ public class DrawerActivity extends ActionBarActivity {
supportInvalidateOptionsMenu(); supportInvalidateOptionsMenu();
// call intent activity if selected // call intent activity if selected
if(mSelectedItem != null) { if (mSelectedItem != null) {
finish(); finish();
overridePendingTransition(0, 0); overridePendingTransition(0, 0);
@ -149,18 +142,18 @@ public class DrawerActivity extends ActionBarActivity {
} }
switch (item.getItemId()) { switch (item.getItemId()) {
case MENU_ID_PREFERENCE: { case MENU_ID_PREFERENCE: {
Intent intent = new Intent(this, PreferencesActivity.class); Intent intent = new Intent(this, PreferencesActivity.class);
startActivity(intent); startActivity(intent);
return true; return true;
} }
case MENU_ID_HELP: { case MENU_ID_HELP: {
Intent intent = new Intent(this, HelpActivity.class); Intent intent = new Intent(this, HelpActivity.class);
startActivity(intent); startActivity(intent);
return true; return true;
} }
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
// Handle action buttons // Handle action buttons
@ -228,15 +221,15 @@ public class DrawerActivity extends ActionBarActivity {
} }
private class NavigationDrawerAdapter extends ArrayAdapter<NavItem> { private class NavigationDrawerAdapter extends ArrayAdapter<NavItem> {
Context context; Context mContext;
int layoutResourceId; int mLayoutResourceId;
NavItem data[] = null; NavItem mData[] = null;
public NavigationDrawerAdapter(Context context, int layoutResourceId, NavItem[] data) { public NavigationDrawerAdapter(Context context, int layoutResourceId, NavItem[] data) {
super(context, layoutResourceId, data); super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId; this.mLayoutResourceId = layoutResourceId;
this.context = context; this.mContext = context;
this.data = data; this.mData = data;
} }
@Override @Override
@ -245,21 +238,21 @@ public class DrawerActivity extends ActionBarActivity {
NavItemHolder holder = null; NavItemHolder holder = null;
if (row == null) { if (row == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater(); LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false); row = inflater.inflate(mLayoutResourceId, parent, false);
holder = new NavItemHolder(); holder = new NavItemHolder();
holder.img = (FontAwesomeText) row.findViewById(R.id.drawer_item_icon); holder.mImg = (FontAwesomeText) row.findViewById(R.id.drawer_item_icon);
holder.txtTitle = (TextView) row.findViewById(R.id.drawer_item_text); holder.mTxtTitle = (TextView) row.findViewById(R.id.drawer_item_text);
row.setTag(holder); row.setTag(holder);
} else { } else {
holder = (NavItemHolder) row.getTag(); holder = (NavItemHolder) row.getTag();
} }
NavItem item = data[position]; NavItem item = mData[position];
holder.txtTitle.setText(item.title); holder.mTxtTitle.setText(item.title);
holder.img.setIcon(item.icon); holder.mImg.setIcon(item.icon);
return row; return row;
} }
@ -267,8 +260,8 @@ public class DrawerActivity extends ActionBarActivity {
} }
static class NavItemHolder { static class NavItemHolder {
FontAwesomeText img; FontAwesomeText mImg;
TextView txtTitle; TextView mTxtTitle;
} }
} }

View File

@ -17,10 +17,25 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList; import android.app.Activity;
import java.util.GregorianCalendar; import android.app.ProgressDialog;
import java.util.Vector; 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.v7.app.ActionBarActivity;
import android.view.*;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
@ -44,30 +59,9 @@ import org.sufficientlysecure.keychain.ui.widget.UserIdEditor;
import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity; import java.util.ArrayList;
import android.app.ProgressDialog; import java.util.GregorianCalendar;
import android.content.Context; import java.util.Vector;
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.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
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 android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton;
public class EditKeyActivity extends ActionBarActivity { public class EditKeyActivity extends ActionBarActivity {
@ -104,7 +98,7 @@ public class EditKeyActivity extends ActionBarActivity {
Vector<String> mUserIds; Vector<String> mUserIds;
Vector<PGPSecretKey> mKeys; Vector<PGPSecretKey> mKeys;
Vector<Integer> mKeysUsages; Vector<Integer> mKeysUsages;
boolean masterCanSign = true; boolean mMasterCanSign = true;
ExportHelper mExportHelper; ExportHelper mExportHelper;
@ -130,7 +124,7 @@ public class EditKeyActivity extends ActionBarActivity {
/** /**
* Handle intent action to create new key * Handle intent action to create new key
* *
* @param intent * @param intent
*/ */
private void handleActionCreateKey(Intent intent) { private void handleActionCreateKey(Intent intent) {
@ -146,7 +140,8 @@ public class EditKeyActivity extends ActionBarActivity {
public void onClick(View v) { public void onClick(View v) {
cancelClicked(); cancelClicked();
} }
}); }
);
Bundle extras = intent.getExtras(); Bundle extras = intent.getExtras();
@ -245,7 +240,7 @@ public class EditKeyActivity extends ActionBarActivity {
/** /**
* Handle intent action to edit existing key * Handle intent action to edit existing key
* *
* @param intent * @param intent
*/ */
private void handleActionEditKey(Intent intent) { private void handleActionEditKey(Intent intent) {
@ -269,8 +264,8 @@ public class EditKeyActivity extends ActionBarActivity {
// get master key id using row id // get master key id using row id
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri); long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
masterCanSign = ProviderHelper.getMasterKeyCanSign(this, mDataUri); mMasterCanSign = ProviderHelper.getMasterKeyCanSign(this, mDataUri);
finallyEdit(masterKeyId, masterCanSign); finallyEdit(masterKeyId, mMasterCanSign);
} }
} }
@ -323,28 +318,28 @@ public class EditKeyActivity extends ActionBarActivity {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_key_edit_cancel: case R.id.menu_key_edit_cancel:
cancelClicked(); cancelClicked();
return true; return true;
case R.id.menu_key_edit_export_file: case R.id.menu_key_edit_export_file:
long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())}; long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())};
mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.path.APP_DIR_FILE_SEC); mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC);
return true; return true;
case R.id.menu_key_edit_delete: { case R.id.menu_key_edit_delete: {
// Message is received after key is deleted // Message is received after key is deleted
Handler returnHandler = new Handler() { Handler returnHandler = new Handler() {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) { if (message.what == DeleteKeyDialogFragment.MESSAGE_OKAY) {
setResult(RESULT_CANCELED); setResult(RESULT_CANCELED);
finish(); finish();
}
} }
} };
};
mExportHelper.deleteKey(mDataUri, Id.type.secret_key, returnHandler); mExportHelper.deleteKey(mDataUri, Id.type.secret_key, returnHandler);
return true; return true;
} }
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@ -437,12 +432,12 @@ public class EditKeyActivity extends ActionBarActivity {
LinearLayout container = (LinearLayout) findViewById(R.id.edit_key_container); LinearLayout container = (LinearLayout) findViewById(R.id.edit_key_container);
mUserIdsView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false); mUserIdsView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
mUserIdsView.setType(Id.type.user_id); mUserIdsView.setType(Id.type.user_id);
mUserIdsView.setCanEdit(masterCanSign); mUserIdsView.setCanEdit(mMasterCanSign);
mUserIdsView.setUserIds(mUserIds); mUserIdsView.setUserIds(mUserIds);
container.addView(mUserIdsView); container.addView(mUserIdsView);
mKeysView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false); mKeysView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
mKeysView.setType(Id.type.key); mKeysView.setType(Id.type.key);
mKeysView.setCanEdit(masterCanSign); mKeysView.setCanEdit(mMasterCanSign);
mKeysView.setKeys(mKeys, mKeysUsages); mKeysView.setKeys(mKeys, mKeysUsages);
container.addView(mKeysView); container.addView(mKeysView);
@ -498,12 +493,13 @@ public class EditKeyActivity extends ActionBarActivity {
} }
String passphrase = null; String passphrase = null;
if (mIsPassPhraseSet) if (mIsPassPhraseSet) {
passphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId); passphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId);
else } else {
passphrase = ""; passphrase = "";
}
if (passphrase == null) { if (passphrase == null) {
showPassphraseDialog(masterKeyId, masterCanSign); showPassphraseDialog(masterKeyId, mMasterCanSign);
} else { } else {
mCurrentPassphrase = passphrase; mCurrentPassphrase = passphrase;
finallySaveClicked(); finallySaveClicked();
@ -536,7 +532,7 @@ public class EditKeyActivity extends ActionBarActivity {
data.putSerializable(KeychainIntentService.SAVE_KEYRING_KEYS_EXPIRY_DATES, data.putSerializable(KeychainIntentService.SAVE_KEYRING_KEYS_EXPIRY_DATES,
getKeysExpiryDates(mKeysView)); getKeysExpiryDates(mKeysView));
data.putLong(KeychainIntentService.SAVE_KEYRING_MASTER_KEY_ID, getMasterKeyId()); data.putLong(KeychainIntentService.SAVE_KEYRING_MASTER_KEY_ID, getMasterKeyId());
data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, masterCanSign); data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, mMasterCanSign);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data); intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
@ -584,7 +580,7 @@ public class EditKeyActivity extends ActionBarActivity {
/** /**
* Returns user ids from the SectionView * Returns user ids from the SectionView
* *
* @param userIdsView * @param userIdsView
* @return * @return
*/ */
@ -604,8 +600,6 @@ public class EditKeyActivity extends ActionBarActivity {
} catch (UserIdEditor.NoEmailException e) { } catch (UserIdEditor.NoEmailException e) {
throw new PgpGeneralException( throw new PgpGeneralException(
this.getString(R.string.error_user_id_needs_an_email_address)); this.getString(R.string.error_user_id_needs_an_email_address));
} catch (UserIdEditor.InvalidEmailException e) {
throw new PgpGeneralException(e.getMessage());
} }
if (userId.equals("")) { if (userId.equals("")) {
@ -633,7 +627,7 @@ public class EditKeyActivity extends ActionBarActivity {
/** /**
* Returns keys from the SectionView * Returns keys from the SectionView
* *
* @param keysView * @param keysView
* @return * @return
*/ */
@ -656,7 +650,7 @@ public class EditKeyActivity extends ActionBarActivity {
/** /**
* Returns usage selections of keys from the SectionView * Returns usage selections of keys from the SectionView
* *
* @param keysView * @param keysView
* @return * @return
*/ */

View File

@ -17,9 +17,22 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.io.File; import android.app.ProgressDialog;
import java.util.Vector; 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.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.*;
import com.beardedhen.androidbootstrap.BootstrapButton;
import com.beardedhen.androidbootstrap.FontAwesomeText;
import com.devspark.appmsg.AppMsg;
import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
@ -43,31 +56,8 @@ import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Choice; import org.sufficientlysecure.keychain.util.Choice;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import android.app.ProgressDialog; import java.io.File;
import android.content.Intent; import java.util.Vector;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper;
import com.beardedhen.androidbootstrap.BootstrapButton;
import com.beardedhen.androidbootstrap.FontAwesomeText;
import com.devspark.appmsg.AppMsg;
public class EncryptActivity extends DrawerActivity { public class EncryptActivity extends DrawerActivity {
@ -858,7 +848,7 @@ public class EncryptActivity extends DrawerActivity {
new Choice(Id.choice.compression.zlib, "ZLIB (" new Choice(Id.choice.compression.zlib, "ZLIB ("
+ getString(R.string.compression_fast) + ")"), + getString(R.string.compression_fast) + ")"),
new Choice(Id.choice.compression.bzip2, "BZIP2 (" new Choice(Id.choice.compression.bzip2, "BZIP2 ("
+ getString(R.string.compression_very_slow) + ")"),}; + getString(R.string.compression_very_slow) + ")"), };
ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(this, ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(this,
android.R.layout.simple_spinner_item, choices); android.R.layout.simple_spinner_item, choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

View File

@ -17,11 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.htmltextview.HtmlTextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
@ -31,6 +26,10 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; 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 { public class HelpAboutFragment extends Fragment {
@ -55,7 +54,7 @@ public class HelpAboutFragment extends Fragment {
/** /**
* Get the current package version. * Get the current package version.
* *
* @return The current version. * @return The current version.
*/ */
private String getVersion() { private String getVersion() {
@ -73,4 +72,4 @@ public class HelpAboutFragment extends Fragment {
return result; return result;
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de> * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -17,19 +17,16 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
public class HelpActivity extends ActionBarActivity { public class HelpActivity extends ActionBarActivity {
public static final String EXTRA_SELECTED_TAB = "selectedTab"; public static final String EXTRA_SELECTED_TAB = "selected_tab";
ViewPager mViewPager; ViewPager mViewPager;
TabsAdapter mTabsAdapter; TabsAdapter mTabsAdapter;
@ -59,19 +56,24 @@ public class HelpActivity extends ActionBarActivity {
Bundle startBundle = new Bundle(); Bundle startBundle = new Bundle();
startBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_start); startBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_start);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_start)), mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_start)),
HelpHtmlFragment.class, startBundle, (selectedTab == 0) ); 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(); Bundle nfcBundle = new Bundle();
nfcBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_nfc_beam); nfcBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_nfc_beam);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_nfc_beam)), mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_nfc_beam)),
HelpHtmlFragment.class, nfcBundle, (selectedTab == 1) ); HelpHtmlFragment.class, nfcBundle, (selectedTab == 2));
Bundle changelogBundle = new Bundle(); Bundle changelogBundle = new Bundle();
changelogBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_changelog); changelogBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_changelog);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_changelog)), mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_changelog)),
HelpHtmlFragment.class, changelogBundle, (selectedTab == 2) ); HelpHtmlFragment.class, changelogBundle, (selectedTab == 3));
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_about)), mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_about)),
HelpAboutFragment.class, null, (selectedTab == 3) ); HelpAboutFragment.class, null, (selectedTab == 4));
} }
} }

View File

@ -17,8 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.htmltextview.HtmlTextView;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
@ -27,11 +25,12 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ScrollView; import android.widget.ScrollView;
import org.sufficientlysecure.htmltextview.HtmlTextView;
public class HelpHtmlFragment extends Fragment { public class HelpHtmlFragment extends Fragment {
private Activity mActivity; private Activity mActivity;
private int htmlFile; private int mHtmlFile;
public static final String ARG_HTML_FILE = "htmlFile"; public static final String ARG_HTML_FILE = "htmlFile";
@ -52,8 +51,8 @@ public class HelpHtmlFragment extends Fragment {
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mActivity = getActivity(); mActivity = getActivity();
htmlFile = getArguments().getInt(ARG_HTML_FILE); mHtmlFile = getArguments().getInt(ARG_HTML_FILE);
ScrollView scroller = new ScrollView(mActivity); ScrollView scroller = new ScrollView(mActivity);
HtmlTextView text = new HtmlTextView(mActivity); HtmlTextView text = new HtmlTextView(mActivity);
@ -66,11 +65,11 @@ public class HelpHtmlFragment extends Fragment {
scroller.addView(text); scroller.addView(text);
// load html from raw resource (Parsing handled by HtmlTextView library) // load html from raw resource (Parsing handled by HtmlTextView library)
text.setHtmlFromRawResource(getActivity(), htmlFile); text.setHtmlFromRawResource(getActivity(), mHtmlFile);
// no flickering when clicking textview for Android < 4 // no flickering when clicking textview for Android < 4
text.setTextColor(getResources().getColor(android.R.color.black)); text.setTextColor(getResources().getColor(android.R.color.black));
return scroller; return scroller;
} }
} }

View File

@ -34,10 +34,8 @@ import android.support.v7.app.ActionBar;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import com.devspark.appmsg.AppMsg; import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
@ -169,7 +167,8 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
query = "0x" + fingerprint; query = "0x" + fingerprint;
} }
} else { } else {
Log.e(Constants.TAG, "IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query', 'key_id', or 'fingerprint' extra!"); Log.e(Constants.TAG,
"IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query', 'key_id', or 'fingerprint' extra!");
return; return;
} }
@ -338,7 +337,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
// } else { // } else {
// status.putString( // status.putString(
// EXTRA_ERROR, // EXTRA_ERROR,
// "Scanned fingerprint does NOT match the fingerprint of the received key. You shouldnt trust this key."); // "Scanned fingerprint does NOT match the fingerprint of the received key. You shouldnt trust this key.");
// } // }
// } // }
// } catch (QueryException e) { // } catch (QueryException e) {
@ -400,7 +399,8 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO) AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO)
.show(); .show();
if (bad > 0) { if (bad > 0) {
BadImportKeyDialogFragment badImportKeyDialogFragment = BadImportKeyDialogFragment.newInstance(bad); BadImportKeyDialogFragment badImportKeyDialogFragment =
BadImportKeyDialogFragment.newInstance(bad);
badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog"); badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog");
} }
} }

View File

@ -17,17 +17,15 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
public class ImportKeysClipboardFragment extends Fragment { public class ImportKeysClipboardFragment extends Fragment {
@ -60,8 +58,9 @@ public class ImportKeysClipboardFragment extends Fragment {
public void onClick(View v) { public void onClick(View v) {
CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity()); CharSequence clipboardText = ClipboardReflection.getClipboardText(getActivity());
String sendText = ""; String sendText = "";
if (clipboardText != null) if (clipboardText != null) {
sendText = clipboardText.toString(); sendText = clipboardText.toString();
}
mImportActivity.loadCallback(sendText.getBytes(), null, null, null); mImportActivity.loadCallback(sendText.getBytes(), null, null, null);
} }
}); });

View File

@ -17,11 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
@ -29,8 +24,11 @@ import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.beardedhen.androidbootstrap.BootstrapButton; 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 { public class ImportKeysFileFragment extends Fragment {
private ImportKeysActivity mImportActivity; private ImportKeysActivity mImportActivity;
@ -62,7 +60,7 @@ public class ImportKeysFileFragment extends Fragment {
// open .asc or .gpg files // open .asc or .gpg files
// setting it to text/plain prevents Cynaogenmod's file manager from selecting asc // setting it to text/plain prevents Cynaogenmod's file manager from selecting asc
// or gpg types! // or gpg types!
FileHelper.openFile(ImportKeysFileFragment.this, Constants.path.APP_DIR + "/", FileHelper.openFile(ImportKeysFileFragment.this, Constants.Path.APP_DIR + "/",
"*/*", Id.request.filename); "*/*", Id.request.filename);
} }
}); });

View File

@ -17,25 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
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 android.app.Activity; import android.app.Activity;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -44,8 +25,21 @@ import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
import android.view.View; import android.view.View;
import android.widget.ListView; import android.widget.ListView;
import com.devspark.appmsg.AppMsg; 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.*;
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 public class ImportKeysListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { LoaderManager.LoaderCallbacks<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
@ -184,7 +178,8 @@ public class ImportKeysListFragment extends ListFragment implements
} }
@Override @Override
public Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> onCreateLoader(int id, Bundle args) { public Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>>
onCreateLoader(int id, Bundle args) {
switch (id) { switch (id) {
case LOADER_ID_BYTES: { case LOADER_ID_BYTES: {
InputData inputData = getInputData(mKeyBytes, mDataUri); InputData inputData = getInputData(mKeyBytes, mDataUri);
@ -225,16 +220,16 @@ public class ImportKeysListFragment extends ListFragment implements
switch (loader.getId()) { switch (loader.getId()) {
case LOADER_ID_BYTES: case LOADER_ID_BYTES:
if(error == null){ if (error == null) {
// No error // No error
} else if(error instanceof ImportKeysListLoader.FileHasNoContent) { } else if (error instanceof ImportKeysListLoader.FileHasNoContent) {
AppMsg.makeText(getActivity(), R.string.error_import_file_no_content, AppMsg.makeText(getActivity(), R.string.error_import_file_no_content,
AppMsg.STYLE_ALERT).show(); AppMsg.STYLE_ALERT).show();
} else if(error instanceof ImportKeysListLoader.NonPgpPart) { } else if (error instanceof ImportKeysListLoader.NonPgpPart) {
AppMsg.makeText(getActivity(), AppMsg.makeText(getActivity(),
((ImportKeysListLoader.NonPgpPart) error).getCount() + " " + getResources(). ((ImportKeysListLoader.NonPgpPart) error).getCount() + " " + getResources().
getQuantityString(R.plurals.error_import_non_pgp_part, getQuantityString(R.plurals.error_import_non_pgp_part,
((ImportKeysListLoader.NonPgpPart) error).getCount()), ((ImportKeysListLoader.NonPgpPart) error).getCount()),
new AppMsg.Style(AppMsg.LENGTH_LONG, R.color.confirm)).show(); new AppMsg.Style(AppMsg.LENGTH_LONG, R.color.confirm)).show();
} else { } else {
AppMsg.makeText(getActivity(), R.string.error_generic_report_bug, AppMsg.makeText(getActivity(), R.string.error_generic_report_bug,
@ -244,19 +239,19 @@ public class ImportKeysListFragment extends ListFragment implements
case LOADER_ID_SERVER_QUERY: case LOADER_ID_SERVER_QUERY:
if(error == null) { if (error == null) {
AppMsg.makeText( AppMsg.makeText(
getActivity(), getResources().getQuantityString(R.plurals.keys_found, getActivity(), getResources().getQuantityString(R.plurals.keys_found,
mAdapter.getCount(), mAdapter.getCount()), mAdapter.getCount(), mAdapter.getCount()),
AppMsg.STYLE_INFO AppMsg.STYLE_INFO
).show(); ).show();
} else if(error instanceof KeyServer.InsufficientQuery) { } else if (error instanceof KeyServer.InsufficientQuery) {
AppMsg.makeText(getActivity(), R.string.error_keyserver_insufficient_query, AppMsg.makeText(getActivity(), R.string.error_keyserver_insufficient_query,
AppMsg.STYLE_ALERT).show(); AppMsg.STYLE_ALERT).show();
} else if(error instanceof KeyServer.QueryException) { } else if (error instanceof KeyServer.QueryException) {
AppMsg.makeText(getActivity(), R.string.error_keyserver_query, AppMsg.makeText(getActivity(), R.string.error_keyserver_query,
AppMsg.STYLE_ALERT).show(); AppMsg.STYLE_ALERT).show();
} else if(error instanceof KeyServer.TooManyResponses) { } else if (error instanceof KeyServer.TooManyResponses) {
AppMsg.makeText(getActivity(), R.string.error_keyserver_too_many_responses, AppMsg.makeText(getActivity(), R.string.error_keyserver_too_many_responses,
AppMsg.STYLE_ALERT).show(); AppMsg.STYLE_ALERT).show();
} }

View File

@ -17,8 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.R;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
@ -26,8 +24,8 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.R;
public class ImportKeysNFCFragment extends Fragment { public class ImportKeysNFCFragment extends Fragment {

View File

@ -17,14 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList;
import java.util.Locale;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4;
import org.sufficientlysecure.keychain.util.Log;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -36,9 +28,15 @@ import android.view.ViewGroup;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import com.google.zxing.integration.android.IntentResult; import com.google.zxing.integration.android.IntentResult;
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 { public class ImportKeysQrCodeFragment extends Fragment {
@ -94,45 +92,45 @@ public class ImportKeysQrCodeFragment extends Fragment {
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode & 0xFFFF) { switch (requestCode & 0xFFFF) {
case IntentIntegratorSupportV4.REQUEST_CODE: { case IntentIntegratorSupportV4.REQUEST_CODE: {
IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode, IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode,
resultCode, data); resultCode, data);
if (scanResult != null && scanResult.getFormatName() != null) { if (scanResult != null && scanResult.getFormatName() != null) {
String scannedContent = scanResult.getContents(); String scannedContent = scanResult.getContents();
Log.d(Constants.TAG, "scannedContent: " + scannedContent); Log.d(Constants.TAG, "scannedContent: " + scannedContent);
// look if it's fingerprint only // look if it's fingerprint only
if (scannedContent.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) { if (scannedContent.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) {
importFingerprint(Uri.parse(scanResult.getContents())); importFingerprint(Uri.parse(scanResult.getContents()));
return; 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();
} }
// look if it is the whole key break;
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);
default: break;
super.onActivityResult(requestCode, resultCode, data);
break;
} }
} }

View File

@ -17,11 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.util.Log;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
@ -36,8 +31,11 @@ import android.widget.ArrayAdapter;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton; 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 class ImportKeysServerFragment extends Fragment {
public static final String ARG_QUERY = "query"; public static final String ARG_QUERY = "query";
@ -96,7 +94,8 @@ public class ImportKeysServerFragment extends Fragment {
search(query, keyServer); search(query, keyServer);
// close keyboard after pressing search // close keyboard after pressing search
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); InputMethodManager imm =
(InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mQueryEditText.getWindowToken(), 0); imm.hideSoftInputFromWindow(mQueryEditText.getWindowToken(), 0);
} }
}); });
@ -110,7 +109,6 @@ public class ImportKeysServerFragment extends Fragment {
search(query, keyServer); search(query, keyServer);
// Don't return true to let the keyboard close itself after pressing search // Don't return true to let the keyboard close itself after pressing search
// http://stackoverflow.com/questions/2342620/how-to-hide-keyboard-after-typing-in-edittext-in-android
return false; return false;
} }
return false; return false;

View File

@ -17,15 +17,14 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ExportHelper;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ExportHelper;
public class KeyListActivity extends DrawerActivity { public class KeyListActivity extends DrawerActivity {
@ -53,19 +52,45 @@ public class KeyListActivity extends DrawerActivity {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_key_list_import: case R.id.menu_key_list_import:
Intent intentImport = new Intent(this, ImportKeysActivity.class); Intent intentImport = new Intent(this, ImportKeysActivity.class);
startActivityForResult(intentImport, 0); startActivityForResult(intentImport, 0);
return true; return true;
case R.id.menu_key_list_export: case R.id.menu_key_list_export:
// TODO fix this for unified keylist // TODO fix this for unified keylist
mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.path.APP_DIR_FILE_PUB); mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB);
return true; return true;
default: case R.id.menu_key_list_create:
return super.onOptionsItemSelected(item); createKey();
return true;
case R.id.menu_key_list_create_expert:
createKeyExpert();
return true;
case R.id.menu_key_list_secret_export:
mExportHelper.showExportKeysDialog(null, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC);
return true;
default:
return super.onOptionsItemSelected(item);
} }
} }
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);
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de> * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -17,28 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.helper.ExportHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
@ -46,45 +24,47 @@ import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Color; import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.*;
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.Fragment;
import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader; import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.view.MenuItemCompat; import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView; import android.support.v7.widget.SearchView;
import android.text.Spannable;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.style.ForegroundColorSpan; import android.view.*;
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.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils; import android.view.animation.AnimationUtils;
import android.widget.*;
import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton; 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;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
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.ArrayList;
import java.util.HashMap;
/** /**
* Public key list with sticky list headers. It does _not_ extend ListFragment because it uses * Public key list with sticky list headers. It does _not_ extend ListFragment because it uses
* StickyListHeaders library which does not extend upon ListView. * StickyListHeaders library which does not extend upon ListView.
*/ */
public class KeyListFragment extends Fragment implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener, public class KeyListFragment extends Fragment
implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener,
LoaderManager.LoaderCallbacks<Cursor> { LoaderManager.LoaderCallbacks<Cursor> {
private KeyListAdapter mAdapter; private KeyListAdapter mAdapter;
@ -202,6 +182,23 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
showDeleteKeyDialog(mode, ids); showDeleteKeyDialog(mode, ids);
break; break;
} }
case R.id.menu_key_list_multi_export: {
// todo: public/secret needs to be handled differently here
ids = mStickyList.getWrappedList().getCheckedItemIds();
ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
mExportHelper
.showExportKeysDialog(ids,
Id.type.public_key,
Constants.Path.APP_DIR_FILE_PUB);
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; return true;
} }
@ -254,8 +251,15 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
}; };
static final int INDEX_TYPE = 1; static final int INDEX_TYPE = 1;
static final int INDEX_UID = 3; static final int INDEX_MASTER_KEY_ID = 2;
static final String SORT_ORDER = UserIds.USER_ID + " ASC"; static final int INDEX_USER_ID = 3;
static final int INDEX_IS_REVOKED = 4;
static final String SORT_ORDER =
// show secret before public key
KeychainDatabase.Tables.KEY_RINGS + "." + KeyRings.TYPE + " DESC, "
// sort by user id otherwise
+ UserIds.USER_ID + " ASC";
@Override @Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) { public Loader<Cursor> onCreateLoader(int id, Bundle args) {
@ -310,9 +314,10 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
} else { } else {
viewIntent = new Intent(getActivity(), ViewKeyActivityJB.class); viewIntent = new Intent(getActivity(), ViewKeyActivityJB.class);
} }
viewIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsByMasterKeyIdUri( viewIntent.setData(
Long.toString(mAdapter.getMasterKeyId(position))) KeychainContract
); .KeyRings.buildPublicKeyRingsByMasterKeyIdUri(
Long.toString(mAdapter.getMasterKeyId(position))));
startActivity(viewIntent); startActivity(viewIntent);
} }
@ -349,8 +354,12 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
for (String userId : notDeleted) { for (String userId : notDeleted) {
notDeletedMsg += userId + "\n"; notDeletedMsg += userId + "\n";
} }
Toast.makeText(getActivity(), getString(R.string.error_can_not_delete_contacts, notDeletedMsg) Toast.makeText(getActivity(),
+ getResources().getQuantityString(R.plurals.error_can_not_delete_info, notDeleted.size()), getString(R.string.error_can_not_delete_contacts, notDeletedMsg)
+ getResources()
.getQuantityString(
R.plurals.error_can_not_delete_info,
notDeleted.size()),
Toast.LENGTH_LONG).show(); Toast.LENGTH_LONG).show();
mode.finish(); mode.finish();
@ -452,45 +461,22 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
/** /**
* Implements StickyListHeadersAdapter from library * Implements StickyListHeadersAdapter from library
*/ */
private class KeyListAdapter extends CursorAdapter implements StickyListHeadersAdapter { private class KeyListAdapter extends HighlightQueryCursorAdapter implements StickyListHeadersAdapter {
private LayoutInflater mInflater; private LayoutInflater mInflater;
private int mIndexUserId;
private int mIndexIsRevoked;
private int mMasterKeyId;
private String mCurQuery;
@SuppressLint("UseSparseArrays")
private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>(); private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
public KeyListAdapter(Context context, Cursor c, int flags) { public KeyListAdapter(Context context, Cursor c, int flags) {
super(context, c, flags); super(context, c, flags);
mInflater = LayoutInflater.from(context); mInflater = LayoutInflater.from(context);
initIndex(c);
} }
@Override @Override
public Cursor swapCursor(Cursor newCursor) { public Cursor swapCursor(Cursor newCursor) {
initIndex(newCursor);
return super.swapCursor(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(KeychainContract.UserIds.USER_ID);
mIndexIsRevoked = cursor.getColumnIndexOrThrow(KeychainContract.Keys.IS_REVOKED);
mMasterKeyId = cursor.getColumnIndexOrThrow(KeychainContract.KeyRings.MASTER_KEY_ID);
}
}
/** /**
* Bind cursor data to the item list view * Bind cursor data to the item list view
* <p/> * <p/>
@ -504,15 +490,15 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
String userId = cursor.getString(mIndexUserId); String userId = cursor.getString(INDEX_USER_ID);
String[] userIdSplit = PgpKeyHelper.splitUserId(userId); String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
if (userIdSplit[0] != null) { if (userIdSplit[0] != null) {
mainUserId.setText(highlightSearchQuery(userIdSplit[0])); mainUserId.setText(highlightSearchQuery(userIdSplit[0]));
} else { } else {
mainUserId.setText(R.string.user_id_no_name); mainUserId.setText(R.string.user_id_no_name);
} }
if (userIdSplit[1] != null) { if (userIdSplit[1] != null) {
mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1])); mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1]));
mainUserIdRest.setVisibility(View.VISIBLE); mainUserIdRest.setVisibility(View.VISIBLE);
} else { } else {
mainUserIdRest.setVisibility(View.GONE); mainUserIdRest.setVisibility(View.GONE);
@ -523,12 +509,12 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
Button button = (Button) view.findViewById(R.id.edit); Button button = (Button) view.findViewById(R.id.edit);
TextView revoked = (TextView) view.findViewById(R.id.revoked); TextView revoked = (TextView) view.findViewById(R.id.revoked);
if(cursor.getInt(KeyListFragment.INDEX_TYPE) == KeyTypes.SECRET) { if (cursor.getInt(KeyListFragment.INDEX_TYPE) == KeyTypes.SECRET) {
// this is a secret key - show the edit button // this is a secret key - show the edit button
revoked.setVisibility(View.GONE); revoked.setVisibility(View.GONE);
button.setVisibility(View.VISIBLE); button.setVisibility(View.VISIBLE);
final long id = cursor.getLong(mMasterKeyId); final long id = cursor.getLong(INDEX_MASTER_KEY_ID);
button.setOnClickListener(new OnClickListener() { button.setOnClickListener(new OnClickListener() {
public void onClick(View view) { public void onClick(View view) {
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
@ -545,7 +531,7 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
// this is a public key - hide the edit button, show if it's revoked // this is a public key - hide the edit button, show if it's revoked
button.setVisibility(View.GONE); button.setVisibility(View.GONE);
boolean isRevoked = cursor.getInt(mIndexIsRevoked) > 0; boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
revoked.setVisibility(isRevoked ? View.VISIBLE : View.GONE); revoked.setVisibility(isRevoked ? View.VISIBLE : View.GONE);
} }
} }
@ -553,23 +539,11 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
} }
public long getMasterKeyId(int id) { public long getMasterKeyId(int id) {
if (!mCursor.moveToPosition(id)) { if (!mCursor.moveToPosition(id)) {
throw new IllegalStateException("couldn't move cursor to position " + id); throw new IllegalStateException("couldn't move cursor to position " + id);
} }
return mCursor.getLong(mMasterKeyId); return mCursor.getLong(INDEX_MASTER_KEY_ID);
}
public int getKeyType(int position) {
if (!mCursor.moveToPosition(position)) {
throw new IllegalStateException("couldn't move cursor to position " + position);
}
return mCursor.getInt(KeyListFragment.INDEX_TYPE);
} }
@Override @Override
@ -590,8 +564,8 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
if (convertView == null) { if (convertView == null) {
holder = new HeaderViewHolder(); holder = new HeaderViewHolder();
convertView = mInflater.inflate(R.layout.key_list_header, parent, false); convertView = mInflater.inflate(R.layout.key_list_header, parent, false);
holder.text = (TextView) convertView.findViewById(R.id.stickylist_header_text); holder.mText = (TextView) convertView.findViewById(R.id.stickylist_header_text);
holder.count = (TextView) convertView.findViewById(R.id.contacts_num); holder.mCount = (TextView) convertView.findViewById(R.id.contacts_num);
convertView.setTag(holder); convertView.setTag(holder);
} else { } else {
holder = (HeaderViewHolder) convertView.getTag(); holder = (HeaderViewHolder) convertView.getTag();
@ -607,26 +581,26 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
throw new IllegalStateException("couldn't move cursor to position " + position); throw new IllegalStateException("couldn't move cursor to position " + position);
} }
if(mCursor.getInt(KeyListFragment.INDEX_TYPE) == KeyTypes.SECRET) { if (mCursor.getInt(KeyListFragment.INDEX_TYPE) == KeyTypes.SECRET) {
{ // set contact count { // set contact count
int num = mCursor.getCount(); int num = mCursor.getCount();
String contactsTotal = getResources().getQuantityString(R.plurals.n_contacts, num, num); String contactsTotal = getResources().getQuantityString(R.plurals.n_contacts, num, num);
holder.count.setText(contactsTotal); holder.mCount.setText(contactsTotal);
holder.count.setVisibility(View.VISIBLE); holder.mCount.setVisibility(View.VISIBLE);
} }
holder.text.setText(convertView.getResources().getString(R.string.my_keys)); holder.mText.setText(convertView.getResources().getString(R.string.my_keys));
return convertView; return convertView;
} }
// set header text as first char in user id // set header text as first char in user id
String userId = mCursor.getString(KeyListFragment.INDEX_UID); String userId = mCursor.getString(KeyListFragment.INDEX_USER_ID);
String headerText = convertView.getResources().getString(R.string.user_id_no_name); String headerText = convertView.getResources().getString(R.string.user_id_no_name);
if (userId != null && userId.length() > 0) { if (userId != null && userId.length() > 0) {
headerText = "" + userId.subSequence(0, 1).charAt(0); headerText = "" + userId.subSequence(0, 1).charAt(0);
} }
holder.text.setText(headerText); holder.mText.setText(headerText);
holder.count.setVisibility(View.GONE); holder.mCount.setVisibility(View.GONE);
return convertView; return convertView;
} }
@ -646,11 +620,11 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
} }
// early breakout: all secret keys are assigned id 0 // early breakout: all secret keys are assigned id 0
if(mCursor.getInt(KeyListFragment.INDEX_TYPE) == KeyTypes.SECRET) if (mCursor.getInt(KeyListFragment.INDEX_TYPE) == KeyTypes.SECRET) {
return 1L; return 1L;
}
// otherwise, return the first character of the name as ID // otherwise, return the first character of the name as ID
String userId = mCursor.getString(KeyListFragment.INDEX_UID); String userId = mCursor.getString(KeyListFragment.INDEX_USER_ID);
if (userId != null && userId.length() > 0) { if (userId != null && userId.length() > 0) {
return userId.charAt(0); return userId.charAt(0);
} else { } else {
@ -659,8 +633,8 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
} }
class HeaderViewHolder { class HeaderViewHolder {
TextView text; TextView mText;
TextView count; TextView mCount;
} }
/** /**
@ -675,8 +649,9 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
long[] ids = new long[mSelection.size()]; long[] ids = new long[mSelection.size()];
int i = 0; int i = 0;
// get master key ids // get master key ids
for (int pos : mSelection.keySet()) for (int pos : mSelection.keySet()) {
ids[i++] = mAdapter.getMasterKeyId(pos); ids[i++] = mAdapter.getMasterKeyId(pos);
}
return ids; return ids;
} }
@ -698,43 +673,17 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
/** /**
* Change color for multi-selection * Change color for multi-selection
*/ */
// default color
v.setBackgroundColor(Color.TRANSPARENT);
if (mSelection.get(position) != null) { if (mSelection.get(position) != null) {
// this is a selected position, change color! // selected position color
v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis)); v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
} else {
// default color
v.setBackgroundColor(Color.TRANSPARENT);
} }
return v; return v;
} }
// search highlight methods
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;
}
}
} }
} }

View File

@ -16,6 +16,11 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.preference.*;
import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData; import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
@ -24,24 +29,13 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference; import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference;
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 android.support.v7.app.ActionBarActivity;
import java.util.List; import java.util.List;
@SuppressLint("NewApi") @SuppressLint("NewApi")
public class PreferencesActivity extends PreferenceActivity { public class PreferencesActivity extends PreferenceActivity {
public final static String ACTION_PREFS_GEN = "org.sufficientlysecure.keychain.ui.PREFS_GEN"; public static final String ACTION_PREFS_GEN = "org.sufficientlysecure.keychain.ui.PREFS_GEN";
public final static String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV"; public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV";
private PreferenceScreen mKeyServerPreference = null; private PreferenceScreen mKeyServerPreference = null;
private static Preferences mPreferences; private static Preferences mPreferences;
@ -62,9 +56,9 @@ public class PreferencesActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.gen_preferences); addPreferencesFromResource(R.xml.gen_preferences);
initializePassPassPhraceCacheTtl( initializePassPassPhraceCacheTtl(
(IntegerListPreference) findPreference(Constants.pref.PASS_PHRASE_CACHE_TTL)); (IntegerListPreference) findPreference(Constants.Pref.PASS_PHRASE_CACHE_TTL));
mKeyServerPreference = (PreferenceScreen) findPreference(Constants.pref.KEY_SERVERS); mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS);
String servers[] = mPreferences.getKeyServers(); String servers[] = mPreferences.getKeyServers();
mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers, mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers,
servers.length, servers.length)); servers.length, servers.length));
@ -84,11 +78,11 @@ public class PreferencesActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.adv_preferences); addPreferencesFromResource(R.xml.adv_preferences);
initializeEncryptionAlgorithm( initializeEncryptionAlgorithm(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM)); (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM));
int[] valueIds = new int[] { Id.choice.compression.none, Id.choice.compression.zip, int[] valueIds = new int[]{Id.choice.compression.none, Id.choice.compression.zip,
Id.choice.compression.zlib, Id.choice.compression.bzip2, }; Id.choice.compression.zlib, Id.choice.compression.bzip2, };
String[] entries = new String[] { String[] entries = new String[]{
getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")",
"ZIP (" + getString(R.string.compression_fast) + ")", "ZIP (" + getString(R.string.compression_fast) + ")",
"ZLIB (" + getString(R.string.compression_fast) + ")", "ZLIB (" + getString(R.string.compression_fast) + ")",
@ -99,20 +93,22 @@ public class PreferencesActivity extends PreferenceActivity {
} }
initializeHashAlgorithm( initializeHashAlgorithm(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM), (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM),
valueIds, entries, values); valueIds, entries, values);
initializeMessageCompression( initializeMessageCompression(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION), (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION),
valueIds, entries, values); valueIds, entries, values);
initializeFileCompression( initializeFileCompression(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION), (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION),
entries, values); entries, values);
initializeAsciiArmour((CheckBoxPreference) findPreference(Constants.pref.DEFAULT_ASCII_ARMOUR)); initializeAsciiArmour(
(CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOUR));
initializeForceV3Signatures((CheckBoxPreference) findPreference(Constants.pref.FORCE_V3_SIGNATURES)); initializeForceV3Signatures(
(CheckBoxPreference) findPreference(Constants.Pref.FORCE_V3_SIGNATURES));
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
// Load the legacy preferences headers // Load the legacy preferences headers
@ -149,7 +145,9 @@ public class PreferencesActivity extends PreferenceActivity {
loadHeadersFromResource(R.xml.preference_headers, target); loadHeadersFromResource(R.xml.preference_headers, target);
} }
/** This fragment shows the general preferences in android 3.0+ */ /**
* This fragment shows the general preferences in android 3.0+
*/
public static class GeneralPrefsFragment extends PreferenceFragment { public static class GeneralPrefsFragment extends PreferenceFragment {
private PreferenceScreen mKeyServerPreference = null; private PreferenceScreen mKeyServerPreference = null;
@ -162,9 +160,9 @@ public class PreferencesActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.gen_preferences); addPreferencesFromResource(R.xml.gen_preferences);
initializePassPassPhraceCacheTtl( initializePassPassPhraceCacheTtl(
(IntegerListPreference) findPreference(Constants.pref.PASS_PHRASE_CACHE_TTL)); (IntegerListPreference) findPreference(Constants.Pref.PASS_PHRASE_CACHE_TTL));
mKeyServerPreference = (PreferenceScreen) findPreference(Constants.pref.KEY_SERVERS); mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS);
String servers[] = mPreferences.getKeyServers(); String servers[] = mPreferences.getKeyServers();
mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers, mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers,
servers.length, servers.length)); servers.length, servers.length));
@ -204,7 +202,9 @@ public class PreferencesActivity extends PreferenceActivity {
} }
} }
/** This fragment shows the advanced preferences in android 3.0+ */ /**
* This fragment shows the advanced preferences in android 3.0+
*/
public static class AdvancedPrefsFragment extends PreferenceFragment { public static class AdvancedPrefsFragment extends PreferenceFragment {
@Override @Override
@ -215,11 +215,11 @@ public class PreferencesActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.adv_preferences); addPreferencesFromResource(R.xml.adv_preferences);
initializeEncryptionAlgorithm( initializeEncryptionAlgorithm(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM)); (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM));
int[] valueIds = new int[] { Id.choice.compression.none, Id.choice.compression.zip, int[] valueIds = new int[]{Id.choice.compression.none, Id.choice.compression.zip,
Id.choice.compression.zlib, Id.choice.compression.bzip2, }; Id.choice.compression.zlib, Id.choice.compression.bzip2, };
String[] entries = new String[] { String[] entries = new String[]{
getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")",
"ZIP (" + getString(R.string.compression_fast) + ")", "ZIP (" + getString(R.string.compression_fast) + ")",
"ZLIB (" + getString(R.string.compression_fast) + ")", "ZLIB (" + getString(R.string.compression_fast) + ")",
@ -230,24 +230,26 @@ public class PreferencesActivity extends PreferenceActivity {
} }
initializeHashAlgorithm( initializeHashAlgorithm(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM), (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM),
valueIds, entries, values); valueIds, entries, values);
initializeMessageCompression( initializeMessageCompression(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION), (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION),
valueIds, entries, values); valueIds, entries, values);
initializeFileCompression( initializeFileCompression(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION), (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION),
entries, values); entries, values);
initializeAsciiArmour((CheckBoxPreference) findPreference(Constants.pref.DEFAULT_ASCII_ARMOUR)); initializeAsciiArmour(
(CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOUR));
initializeForceV3Signatures((CheckBoxPreference) findPreference(Constants.pref.FORCE_V3_SIGNATURES)); initializeForceV3Signatures(
(CheckBoxPreference) findPreference(Constants.Pref.FORCE_V3_SIGNATURES));
} }
} }
protected boolean isValidFragment (String fragmentName) { protected boolean isValidFragment(String fragmentName) {
return AdvancedPrefsFragment.class.getName().equals(fragmentName) return AdvancedPrefsFragment.class.getName().equals(fragmentName)
|| GeneralPrefsFragment.class.getName().equals(fragmentName) || GeneralPrefsFragment.class.getName().equals(fragmentName)
|| super.isValidFragment(fragmentName); || super.isValidFragment(fragmentName);
@ -268,11 +270,11 @@ public class PreferencesActivity extends PreferenceActivity {
} }
private static void initializeEncryptionAlgorithm(final IntegerListPreference mEncryptionAlgorithm) { private static void initializeEncryptionAlgorithm(final IntegerListPreference mEncryptionAlgorithm) {
int valueIds[] = { PGPEncryptedData.AES_128, PGPEncryptedData.AES_192, int valueIds[] = {PGPEncryptedData.AES_128, PGPEncryptedData.AES_192,
PGPEncryptedData.AES_256, PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH, PGPEncryptedData.AES_256, PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH,
PGPEncryptedData.CAST5, PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES, PGPEncryptedData.CAST5, PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES,
PGPEncryptedData.IDEA, }; PGPEncryptedData.IDEA, };
String entries[] = { "AES-128", "AES-192", "AES-256", "Blowfish", "Twofish", "CAST5", String entries[] = {"AES-128", "AES-192", "AES-256", "Blowfish", "Twofish", "CAST5",
"DES", "Triple DES", "IDEA", }; "DES", "Triple DES", "IDEA", };
String values[] = new String[valueIds.length]; String values[] = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) { for (int i = 0; i < values.length; ++i) {
@ -296,10 +298,10 @@ public class PreferencesActivity extends PreferenceActivity {
private static void initializeHashAlgorithm private static void initializeHashAlgorithm
(final IntegerListPreference mHashAlgorithm, int[] valueIds, String[] entries, String[] values) { (final IntegerListPreference mHashAlgorithm, int[] valueIds, String[] entries, String[] values) {
valueIds = new int[] { HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160, valueIds = new int[]{HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160,
HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256, HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256,
HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512, }; HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512, };
entries = new String[] { "MD5", "RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384", entries = new String[]{"MD5", "RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384",
"SHA-512", }; "SHA-512", };
values = new String[valueIds.length]; values = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) { for (int i = 0; i < values.length; ++i) {
@ -319,8 +321,9 @@ public class PreferencesActivity extends PreferenceActivity {
}); });
} }
private static void initializeMessageCompression private static void initializeMessageCompression(
(final IntegerListPreference mMessageCompression, int[] valueIds, String[] entries, String[] values) { final IntegerListPreference mMessageCompression,
int[] valueIds, String[] entries, String[] values) {
mMessageCompression.setEntries(entries); mMessageCompression.setEntries(entries);
mMessageCompression.setEntryValues(values); mMessageCompression.setEntryValues(values);
mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression()); mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression());
@ -375,4 +378,4 @@ public class PreferencesActivity extends PreferenceActivity {
} }
}); });
} }
} }

View File

@ -16,14 +16,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.util.Vector;
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 android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
@ -33,6 +25,13 @@ import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; 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, public class PreferencesKeyServerActivity extends ActionBarActivity implements OnClickListener,
EditorListener { EditorListener {
@ -63,7 +62,8 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O
// cancel // cancel
cancelClicked(); cancelClicked();
} }
}); }
);
setContentView(R.layout.key_server_preference); setContentView(R.layout.key_server_preference);

View File

@ -17,14 +17,13 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.view.View; 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 { public class SelectPublicKeyActivity extends ActionBarActivity {
@ -39,7 +38,7 @@ public class SelectPublicKeyActivity extends ActionBarActivity {
SelectPublicKeyFragment mSelectFragment; SelectPublicKeyFragment mSelectFragment;
long selectedMasterKeyIds[]; long mSelectedMasterKeyIds[];
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -59,7 +58,8 @@ public class SelectPublicKeyActivity extends ActionBarActivity {
// cancel // cancel
cancelClicked(); cancelClicked();
} }
}); }
);
setContentView(R.layout.select_public_key_activity); setContentView(R.layout.select_public_key_activity);
@ -79,7 +79,7 @@ public class SelectPublicKeyActivity extends ActionBarActivity {
} }
// Create an instance of the fragment // Create an instance of the fragment
mSelectFragment = SelectPublicKeyFragment.newInstance(selectedMasterKeyIds); mSelectFragment = SelectPublicKeyFragment.newInstance(mSelectedMasterKeyIds);
// Add the fragment to the 'fragment_container' FrameLayout // Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
@ -124,7 +124,7 @@ public class SelectPublicKeyActivity extends ActionBarActivity {
// } // }
// preselected master keys // preselected master keys
selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); mSelectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
} }
private void cancelClicked() { private void cancelClicked() {

View File

@ -17,19 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.util.Date;
import java.util.Vector;
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 android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.DatabaseUtils; import android.database.DatabaseUtils;
@ -45,12 +32,19 @@ import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.EditText; import android.widget.*;
import android.widget.FrameLayout; import org.sufficientlysecure.keychain.Id;
import android.widget.LinearLayout; import org.sufficientlysecure.keychain.R;
import android.widget.ListView; import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround;
import android.widget.ProgressBar; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import android.widget.TextView; 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, public class SelectPublicKeyFragment extends ListFragmentWorkaround implements TextWatcher,
LoaderManager.LoaderCallbacks<Cursor> { LoaderManager.LoaderCallbacks<Cursor> {
@ -138,7 +132,8 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
mSearchView = new EditText(context); mSearchView = new EditText(context);
mSearchView.setId(SEARCH_ID); mSearchView.setId(SEARCH_ID);
mSearchView.setHint(R.string.menu_search); mSearchView.setHint(R.string.menu_search);
mSearchView.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.ic_action_search), null, null, null); mSearchView.setCompoundDrawablesWithIntrinsicBounds(
getResources().getDrawable(R.drawable.ic_action_search), null, null, null);
linearLayout.addView(mSearchView, new FrameLayout.LayoutParams( linearLayout.addView(mSearchView, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
@ -276,7 +271,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
+ Keys.CAN_ENCRYPT + " = '1' AND valid_keys." + Keys.CREATION + " <= '" + Keys.CAN_ENCRYPT + " = '1' AND valid_keys." + Keys.CREATION + " <= '"
+ now + "' AND " + "(valid_keys." + Keys.EXPIRY + " IS NULL OR valid_keys." + now + "' AND " + "(valid_keys." + Keys.EXPIRY + " IS NULL OR valid_keys."
+ Keys.EXPIRY + " >= '" + now + "')) AS " + Keys.EXPIRY + " >= '" + now + "')) AS "
+ SelectKeyCursorAdapter.PROJECTION_ROW_VALID,}; + SelectKeyCursorAdapter.PROJECTION_ROW_VALID, };
String inMasterKeyList = null; String inMasterKeyList = null;
if (mSelectedMasterKeyIds != null && mSelectedMasterKeyIds.length > 0) { if (mSelectedMasterKeyIds != null && mSelectedMasterKeyIds.length > 0) {

View File

@ -17,14 +17,13 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.view.Menu; import android.view.Menu;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
public class SelectSecretKeyActivity extends ActionBarActivity { public class SelectSecretKeyActivity extends ActionBarActivity {
@ -90,7 +89,7 @@ public class SelectSecretKeyActivity extends ActionBarActivity {
/** /**
* This is executed by SelectSecretKeyFragment after clicking on an item * This is executed by SelectSecretKeyFragment after clicking on an item
* *
* @param masterKeyId * @param masterKeyId
* @param userId * @param userId
*/ */

View File

@ -17,17 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.util.Date;
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 android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -39,6 +28,16 @@ import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView; 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 public class SelectSecretKeyFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor> { LoaderManager.LoaderCallbacks<Cursor> {
@ -46,9 +45,9 @@ public class SelectSecretKeyFragment extends ListFragment implements
private SelectSecretKeyActivity mActivity; private SelectSecretKeyActivity mActivity;
private SelectKeyCursorAdapter mAdapter; private SelectKeyCursorAdapter mAdapter;
private ListView mListView; private ListView mListView;
private boolean mFilterCertify; private boolean mFilterCertify;
private static final String ARG_FILTER_CERTIFY = "filter_certify"; private static final String ARG_FILTER_CERTIFY = "filter_certify";
/** /**
@ -122,7 +121,7 @@ public class SelectSecretKeyFragment extends ListFragment implements
// These are the rows that we will retrieve. // These are the rows that we will retrieve.
long now = new Date().getTime() / 1000; long now = new Date().getTime() / 1000;
String[] projection = new String[] { String[] projection = new String[]{
KeyRings._ID, KeyRings._ID,
KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID,
UserIds.USER_ID, UserIds.USER_ID,

View File

@ -17,6 +17,16 @@
package org.sufficientlysecure.keychain.ui; 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.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
@ -24,21 +34,6 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import android.Manifest;
import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
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;
public class SelectSecretKeyLayoutFragment extends Fragment { public class SelectSecretKeyLayoutFragment extends Fragment {
private TextView mKeyUserId; private TextView mKeyUserId;
@ -106,7 +101,10 @@ public class SelectSecretKeyLayoutFragment extends Fragment {
mKeyUserIdRest.setVisibility(View.GONE); mKeyUserIdRest.setVisibility(View.GONE);
} }
} else { } else {
mKeyMasterKeyIdHex.setText(getActivity().getResources().getString(R.string.no_keys_added_or_updated) + " for master id: " + secretKeyId); mKeyMasterKeyIdHex.setText(
getActivity().getResources()
.getString(R.string.no_keys_added_or_updated)
+ " for master id: " + secretKeyId);
mKeyUserId.setVisibility(View.GONE); mKeyUserId.setVisibility(View.GONE);
mKeyUserIdRest.setVisibility(View.GONE); mKeyUserIdRest.setVisibility(View.GONE);
} }

View File

@ -17,13 +17,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
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;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
@ -36,8 +29,13 @@ import android.view.View.OnClickListener;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.Toast; import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton; 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 * Sends the selected public key to a keyserver
@ -59,7 +57,7 @@ public class UploadKeyActivity extends ActionBarActivity {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, Preferences.getPreferences(this) android.R.layout.simple_spinner_item, Preferences.getPreferences(this)
.getKeyServers()); .getKeyServers());
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mKeyServerSpinner.setAdapter(adapter); mKeyServerSpinner.setAdapter(adapter);
if (adapter.getCount() > 0) { if (adapter.getCount() > 0) {

View File

@ -29,7 +29,6 @@ import android.support.v7.app.ActionBarActivity;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.Toast; import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@ -88,7 +87,7 @@ public class ViewKeyActivity extends ActionBarActivity {
// given valid /public/ query // given valid /public/ query
long rowId = ProviderHelper.getRowId(this, getIntent().getData()); long rowId = ProviderHelper.getRowId(this, getIntent().getData());
// TODO: handle (rowId == 0) with something else than a crash // TODO: handle (rowId == 0) with something else than a crash
mDataUri = KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(rowId)) ; mDataUri = KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(rowId));
Bundle mainBundle = new Bundle(); Bundle mainBundle = new Bundle();
mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, mDataUri); mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, mDataUri);
@ -124,7 +123,7 @@ public class ViewKeyActivity extends ActionBarActivity {
return true; return true;
case R.id.menu_key_view_export_file: case R.id.menu_key_view_export_file:
long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())}; long[] ids = new long[]{Long.valueOf(mDataUri.getLastPathSegment())};
mExportHelper.showExportKeysDialog(ids, Id.type.public_key, Constants.path.APP_DIR_FILE_PUB); mExportHelper.showExportKeysDialog(ids, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB);
return true; return true;
case R.id.menu_key_view_share_default_fingerprint: case R.id.menu_key_view_share_default_fingerprint:
shareKey(mDataUri, true); shareKey(mDataUri, true);
@ -240,7 +239,8 @@ public class ViewKeyActivity extends ActionBarActivity {
// we delete only this key, so MESSAGE_NOT_DELETED will solely contain this key // we delete only this key, so MESSAGE_NOT_DELETED will solely contain this key
Toast.makeText(ViewKeyActivity.this, Toast.makeText(ViewKeyActivity.this,
getString(R.string.error_can_not_delete_contact) getString(R.string.error_can_not_delete_contact)
+ getResources().getQuantityString(R.plurals.error_can_not_delete_info, 1), + getResources()
.getQuantityString(R.plurals.error_can_not_delete_info, 1),
Toast.LENGTH_LONG).show(); Toast.LENGTH_LONG).show();
} else { } else {
setResult(RESULT_CANCELED); setResult(RESULT_CANCELED);

View File

@ -18,10 +18,6 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.net.Uri; import android.net.Uri;
import android.nfc.NdefMessage; import android.nfc.NdefMessage;
@ -35,6 +31,9 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.widget.Toast; import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMessageCallback, public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMessageCallback,
@ -66,7 +65,7 @@ public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMess
// get public keyring as byte array // get public keyring as byte array
long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
mSharedKeyringBytes = ProviderHelper.getKeyRingsAsByteArray(this, dataUri, mSharedKeyringBytes = ProviderHelper.getKeyRingsAsByteArray(this, dataUri,
new long[] { masterKeyId }); new long[]{masterKeyId});
// Register callback to set NDEF message // Register callback to set NDEF message
mNfcAdapter.setNdefPushMessageCallback(this, this); mNfcAdapter.setNdefPushMessageCallback(this, this);
@ -109,10 +108,10 @@ public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMess
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
switch (msg.what) { switch (msg.what) {
case NFC_SENT: case NFC_SENT:
Toast.makeText(getApplicationContext(), R.string.nfc_successfull, Toast.LENGTH_LONG) Toast.makeText(getApplicationContext(), R.string.nfc_successfull, Toast.LENGTH_LONG)
.show(); .show();
break; break;
} }
} }
}; };

View File

@ -42,6 +42,8 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import com.beardedhen.androidbootstrap.BootstrapButton;
import se.emilsjolander.stickylistheaders.ApiLevelTooLowException; import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
import se.emilsjolander.stickylistheaders.StickyListHeadersListView; import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
@ -313,4 +315,4 @@ public class ViewKeyCertsFragment extends Fragment
} }
} }

View File

@ -35,11 +35,10 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.KeychainDatabase;
@ -52,7 +51,7 @@ import java.util.Date;
public class ViewKeyMainFragment extends Fragment implements public class ViewKeyMainFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor>{ LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri"; public static final String ARG_DATA_URI = "uri";
@ -129,7 +128,7 @@ public class ViewKeyMainFragment extends Fragment implements
{ // label whether secret key is available, and edit button if it is { // label whether secret key is available, and edit button if it is
final long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), mDataUri); final long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), mDataUri);
if(ProviderHelper.hasSecretKeyByMasterKeyId(getActivity(), masterKeyId)) { if (ProviderHelper.hasSecretKeyByMasterKeyId(getActivity(), masterKeyId)) {
// set this attribute. this is a LITTLE unclean, but we have the info available // set this attribute. this is a LITTLE unclean, but we have the info available
// right here, so why not. // right here, so why not.
mSecretKey.setTextColor(getResources().getColor(R.color.emphasis)); mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
@ -143,7 +142,10 @@ public class ViewKeyMainFragment extends Fragment implements
mActionEdit.setOnClickListener(new View.OnClickListener() { mActionEdit.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) { public void onClick(View view) {
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
editIntent.setData(KeychainContract.KeyRings.buildSecretKeyRingsByMasterKeyIdUri(Long.toString(masterKeyId))); editIntent.setData(
KeychainContract
.KeyRings.buildSecretKeyRingsByMasterKeyIdUri(
Long.toString(masterKeyId)));
editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY); editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
startActivityForResult(editIntent, 0); startActivityForResult(editIntent, 0);
} }
@ -188,21 +190,29 @@ public class ViewKeyMainFragment extends Fragment implements
getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this); getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this);
} }
static final String[] KEYRING_PROJECTION = new String[]{KeychainContract.KeyRings._ID, KeychainContract.KeyRings.MASTER_KEY_ID, static final String[] KEYRING_PROJECTION =
new String[]{KeychainContract.KeyRings._ID, KeychainContract.KeyRings.MASTER_KEY_ID,
KeychainContract.UserIds.USER_ID}; KeychainContract.UserIds.USER_ID};
static final int KEYRING_INDEX_ID = 0; static final int KEYRING_INDEX_ID = 0;
static final int KEYRING_INDEX_MASTER_KEY_ID = 1; static final int KEYRING_INDEX_MASTER_KEY_ID = 1;
static final int KEYRING_INDEX_USER_ID = 2; static final int KEYRING_INDEX_USER_ID = 2;
static final String[] USER_IDS_PROJECTION = new String[]{ KeychainContract.UserIds._ID, KeychainContract.UserIds.USER_ID, static final String[] USER_IDS_PROJECTION =
KeychainContract.UserIds.RANK, "verified" }; new String[]{KeychainContract.UserIds._ID, KeychainContract.UserIds.USER_ID,
KeychainContract.UserIds.RANK, };
// not the main user id // not the main user id
static final String USER_IDS_SELECTION = KeychainDatabase.Tables.USER_IDS + "." + KeychainContract.UserIds.RANK + " > 0 "; static final String USER_IDS_SELECTION =
static final String USER_IDS_SORT_ORDER = KeychainContract.UserIds.USER_ID + " COLLATE LOCALIZED ASC"; KeychainDatabase.Tables.USER_IDS + "." + KeychainContract.UserIds.RANK + " > 0 ";
static final String USER_IDS_SORT_ORDER =
KeychainDatabase.Tables.USER_IDS + "." + KeychainContract.UserIds.USER_ID + " COLLATE LOCALIZED ASC";
static final String[] KEYS_PROJECTION = new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID, static final String[] KEYS_PROJECTION =
KeychainContract.Keys.IS_MASTER_KEY, KeychainContract.Keys.ALGORITHM, KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY, KeychainContract.Keys.CAN_SIGN, new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID,
KeychainContract.Keys.CAN_ENCRYPT, KeychainContract.Keys.CREATION, KeychainContract.Keys.EXPIRY, KeychainContract.Keys.FINGERPRINT}; KeychainContract.Keys.IS_MASTER_KEY, KeychainContract.Keys.ALGORITHM,
KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY,
KeychainContract.Keys.CAN_SIGN, KeychainContract.Keys.CAN_ENCRYPT,
KeychainContract.Keys.CREATION, KeychainContract.Keys.EXPIRY,
KeychainContract.Keys.FINGERPRINT};
static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC"; static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC";
static final int KEYS_INDEX_ID = 0; static final int KEYS_INDEX_ID = 0;
static final int KEYS_INDEX_KEY_ID = 1; static final int KEYS_INDEX_KEY_ID = 1;
@ -285,7 +295,8 @@ public class ViewKeyMainFragment extends Fragment implements
} else { } else {
Date creationDate = new Date(data.getLong(KEYS_INDEX_CREATION) * 1000); Date creationDate = new Date(data.getLong(KEYS_INDEX_CREATION) * 1000);
mCreation.setText(DateFormat.getDateFormat(getActivity().getApplicationContext()).format( mCreation.setText(
DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
creationDate)); creationDate));
} }
@ -295,7 +306,8 @@ public class ViewKeyMainFragment extends Fragment implements
} else { } else {
Date expiryDate = new Date(data.getLong(KEYS_INDEX_EXPIRY) * 1000); Date expiryDate = new Date(data.getLong(KEYS_INDEX_EXPIRY) * 1000);
mExpiry.setText(DateFormat.getDateFormat(getActivity().getApplicationContext()).format( mExpiry.setText(
DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
expiryDate)); expiryDate));
} }
@ -323,18 +335,56 @@ public class ViewKeyMainFragment extends Fragment implements
private SpannableStringBuilder colorizeFingerprint(String fingerprint) { private SpannableStringBuilder colorizeFingerprint(String fingerprint) {
SpannableStringBuilder sb = new SpannableStringBuilder(fingerprint); SpannableStringBuilder sb = new SpannableStringBuilder(fingerprint);
ForegroundColorSpan fcs = new ForegroundColorSpan(Color.BLACK); 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);
// for each 4 characters of the fingerprint + 1 space int raw = Integer.parseInt(fourChars, 16);
for (int i = 0; i < fingerprint.length(); i += 5) { byte[] bytes = {(byte) ((raw >> 8) & 0xff - 128), (byte) (raw & 0xff - 128)};
int minFingLength = Math.min(i + 4, fingerprint.length()); int[] color = OtherHelper.getRgbForData(bytes);
String fourChars = fingerprint.substring(i, minFingLength); int r = color[0];
int g = color[1];
int b = color[2];
// Create a foreground color by converting the 4 fingerprint chars to an int hashcode // we cannot change black by multiplication, so adjust it to an almost-black grey,
// and then converting that int to hex to use as a color // which will then be brightened to the minimal brightness level
fcs = new ForegroundColorSpan( if (r == 0 && g == 0 && b == 0) {
Color.parseColor(String.format("#%06X", (0xFFFFFF & fourChars.hashCode())))); r = 1;
sb.setSpan(fcs, i, minFingLength, Spannable.SPAN_INCLUSIVE_INCLUSIVE); 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; return sb;
@ -377,5 +427,4 @@ public class ViewKeyMainFragment extends Fragment implements
startActivity(signIntent); startActivity(signIntent);
} }
}
}

View File

@ -22,24 +22,25 @@ package org.sufficientlysecure.keychain.ui.adapter;
* You can pass the result and an exception in it if an error occurred. * You can pass the result and an exception in it if an error occurred.
* Concept found at: * Concept found at:
* https://stackoverflow.com/questions/19593577/how-to-handle-errors-in-custom-asynctaskloader * https://stackoverflow.com/questions/19593577/how-to-handle-errors-in-custom-asynctaskloader
*
* @param <T> - Typ of the result which is wrapped * @param <T> - Typ of the result which is wrapped
*/ */
public class AsyncTaskResultWrapper <T>{ public class AsyncTaskResultWrapper<T> {
private final T result; private final T mResult;
private final Exception error; private final Exception mError;
public AsyncTaskResultWrapper(T result, Exception error){ public AsyncTaskResultWrapper(T result, Exception error) {
this.result = result; this.mResult = result;
this.error = error; this.mError = error;
} }
public T getResult() { public T getResult() {
return result; return mResult;
} }
public Exception getError() { public Exception getError() {
return error; return mError;
} }
} }

View File

@ -22,7 +22,6 @@ import android.database.Cursor;
import android.support.v4.widget.CursorAdapter; import android.support.v4.widget.CursorAdapter;
import android.text.Spannable; import android.text.Spannable;
import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import java.util.regex.Matcher; import java.util.regex.Matcher;

View File

@ -17,12 +17,6 @@
package org.sufficientlysecure.keychain.ui.adapter; package org.sufficientlysecure.keychain.ui.adapter;
import java.util.ArrayList;
import java.util.List;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
@ -36,21 +30,28 @@ import android.widget.CheckBox;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams; import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView; 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> { public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
protected LayoutInflater mInflater; protected LayoutInflater mInflater;
protected Activity mActivity; protected Activity mActivity;
protected List<ImportKeysListEntry> data; protected List<ImportKeysListEntry> mData;
static class ViewHolder{
private TextView mainUserId; static class ViewHolder {
private TextView mainUserIdRest; private TextView mMainUserId;
private TextView keyId; private TextView mMainUserIdRest;
private TextView fingerprint; private TextView mKeyId;
private TextView algorithm; private TextView mFingerprint;
private TextView status; private TextView mAlgorithm;
private TextView mStatus;
} }
public ImportKeysAdapter(Activity activity) { public ImportKeysAdapter(Activity activity) {
super(activity, -1); super(activity, -1);
mActivity = activity; mActivity = activity;
@ -61,7 +62,7 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
public void setData(List<ImportKeysListEntry> data) { public void setData(List<ImportKeysListEntry> data) {
clear(); clear();
if (data != null) { if (data != null) {
this.data = data; this.mData = data;
// add data to extended ArrayAdapter // add data to extended ArrayAdapter
if (Build.VERSION.SDK_INT >= 11) { if (Build.VERSION.SDK_INT >= 11) {
@ -75,14 +76,15 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
} }
public List<ImportKeysListEntry> getData() { public List<ImportKeysListEntry> getData() {
return data; return mData;
} }
public ArrayList<ImportKeysListEntry> getSelectedData() { public ArrayList<ImportKeysListEntry> getSelectedData() {
ArrayList<ImportKeysListEntry> selectedData = new ArrayList<ImportKeysListEntry>(); ArrayList<ImportKeysListEntry> selectedData = new ArrayList<ImportKeysListEntry>();
for (ImportKeysListEntry entry : data) { for (ImportKeysListEntry entry : mData) {
if (entry.isSelected()) if (entry.isSelected()) {
selectedData.add(entry); selectedData.add(entry);
}
} }
return selectedData; return selectedData;
} }
@ -93,21 +95,20 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
} }
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
ImportKeysListEntry entry = data.get(position); ImportKeysListEntry entry = mData.get(position);
ViewHolder holder; ViewHolder holder;
if(convertView == null) { if (convertView == null) {
holder = new ViewHolder(); holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.import_keys_list_entry, null); convertView = mInflater.inflate(R.layout.import_keys_list_entry, null);
holder.mainUserId = (TextView) convertView.findViewById(R.id.mainUserId); holder.mMainUserId = (TextView) convertView.findViewById(R.id.mainUserId);
holder.mainUserIdRest = (TextView) convertView.findViewById(R.id.mainUserIdRest); holder.mMainUserIdRest = (TextView) convertView.findViewById(R.id.mainUserIdRest);
holder.keyId = (TextView) convertView.findViewById(R.id.keyId); holder.mKeyId = (TextView) convertView.findViewById(R.id.keyId);
holder.fingerprint = (TextView) convertView.findViewById(R.id.fingerprint); holder.mFingerprint = (TextView) convertView.findViewById(R.id.fingerprint);
holder.algorithm = (TextView) convertView.findViewById(R.id.algorithm); holder.mAlgorithm = (TextView) convertView.findViewById(R.id.algorithm);
holder.status = (TextView) convertView.findViewById(R.id.status); holder.mStatus = (TextView) convertView.findViewById(R.id.status);
convertView.setTag(holder); convertView.setTag(holder);
} } else {
else{ holder = (ViewHolder) convertView.getTag();
holder = (ViewHolder)convertView.getTag();
} }
// main user id // main user id
String userId = entry.userIds.get(0); String userId = entry.userIds.get(0);
@ -118,39 +119,40 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
// show red user id if it is a secret key // show red user id if it is a secret key
if (entry.secretKey) { if (entry.secretKey) {
userIdSplit[0] = mActivity.getString(R.string.secret_key) + " " + userIdSplit[0]; userIdSplit[0] = mActivity.getString(R.string.secret_key) + " " + userIdSplit[0];
holder.mainUserId.setTextColor(Color.RED); holder.mMainUserId.setTextColor(Color.RED);
} }
holder.mainUserId.setText(userIdSplit[0]); holder.mMainUserId.setText(userIdSplit[0]);
} else { } else {
holder.mainUserId.setText(R.string.user_id_no_name); holder.mMainUserId.setText(R.string.user_id_no_name);
} }
// email // email
if (userIdSplit[1] != null) { if (userIdSplit[1] != null) {
holder.mainUserIdRest.setText(userIdSplit[1]); holder.mMainUserIdRest.setText(userIdSplit[1]);
holder.mainUserIdRest.setVisibility(View.VISIBLE); holder.mMainUserIdRest.setVisibility(View.VISIBLE);
} else { } else {
holder.mainUserIdRest.setVisibility(View.GONE); holder.mMainUserIdRest.setVisibility(View.GONE);
} }
holder.keyId.setText(entry.hexKeyId); holder.mKeyId.setText(entry.hexKeyId);
if (entry.fingerPrint != null) { if (entry.fingerPrint != null) {
holder.fingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint); holder.mFingerprint.setText(mActivity.getString(R.string.fingerprint) + " " + entry.fingerPrint);
holder.fingerprint.setVisibility(View.VISIBLE); holder.mFingerprint.setVisibility(View.VISIBLE);
} else { } else {
holder.fingerprint.setVisibility(View.GONE); holder.mFingerprint.setVisibility(View.GONE);
} }
holder.algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm); holder.mAlgorithm.setText("" + entry.bitStrength + "/" + entry.algorithm);
if (entry.revoked) { if (entry.revoked) {
holder.status.setText(R.string.revoked); holder.mStatus.setText(R.string.revoked);
} else { } else {
holder.status.setVisibility(View.GONE); holder.mStatus.setVisibility(View.GONE);
} }
LinearLayout ll = (LinearLayout) convertView.findViewById(R.id.list); LinearLayout ll = (LinearLayout) convertView.findViewById(R.id.list);
ll.removeAllViews();
if (entry.userIds.size() == 1) { if (entry.userIds.size() == 1) {
ll.setVisibility(View.GONE); ll.setVisibility(View.GONE);
} else { } else {

View File

@ -19,12 +19,6 @@ package org.sufficientlysecure.keychain.ui.adapter;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSecretKeyRing;
@ -33,6 +27,11 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log; 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 { public class ImportKeysListEntry implements Serializable, Parcelable {
private static final long serialVersionUID = -7797972103284992662L; private static final long serialVersionUID = -7797972103284992662L;
public ArrayList<String> userIds; public ArrayList<String> userIds;
@ -46,9 +45,9 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
public String algorithm; public String algorithm;
public boolean secretKey; public boolean secretKey;
private boolean selected; private boolean mSelected;
private byte[] bytes = new byte[]{}; private byte[] mBytes = new byte[]{};
public ImportKeysListEntry(ImportKeysListEntry b) { public ImportKeysListEntry(ImportKeysListEntry b) {
this.userIds = b.userIds; this.userIds = b.userIds;
@ -60,8 +59,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
this.bitStrength = b.bitStrength; this.bitStrength = b.bitStrength;
this.algorithm = b.algorithm; this.algorithm = b.algorithm;
this.secretKey = b.secretKey; this.secretKey = b.secretKey;
this.selected = b.selected; this.mSelected = b.mSelected;
this.bytes = b.bytes; this.mBytes = b.mBytes;
} }
public int describeContents() { public int describeContents() {
@ -79,9 +78,9 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
dest.writeInt(bitStrength); dest.writeInt(bitStrength);
dest.writeString(algorithm); dest.writeString(algorithm);
dest.writeByte((byte) (secretKey ? 1 : 0)); dest.writeByte((byte) (secretKey ? 1 : 0));
dest.writeByte((byte) (selected ? 1 : 0)); dest.writeByte((byte) (mSelected ? 1 : 0));
dest.writeInt(bytes.length); dest.writeInt(mBytes.length);
dest.writeByteArray(bytes); dest.writeByteArray(mBytes);
} }
public static final Creator<ImportKeysListEntry> CREATOR = new Creator<ImportKeysListEntry>() { public static final Creator<ImportKeysListEntry> CREATOR = new Creator<ImportKeysListEntry>() {
@ -97,9 +96,9 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
vr.bitStrength = source.readInt(); vr.bitStrength = source.readInt();
vr.algorithm = source.readString(); vr.algorithm = source.readString();
vr.secretKey = source.readByte() == 1; vr.secretKey = source.readByte() == 1;
vr.selected = source.readByte() == 1; vr.mSelected = source.readByte() == 1;
vr.bytes = new byte[source.readInt()]; vr.mBytes = new byte[source.readInt()];
source.readByteArray(vr.bytes); source.readByteArray(vr.mBytes);
return vr; return vr;
} }
@ -114,11 +113,11 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} }
public byte[] getBytes() { public byte[] getBytes() {
return bytes; return mBytes;
} }
public void setBytes(byte[] bytes) { public void setBytes(byte[] bytes) {
this.bytes = bytes; this.mBytes = bytes;
} }
/** /**
@ -128,16 +127,16 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
// keys from keyserver are always public keys // keys from keyserver are always public keys
secretKey = false; secretKey = false;
// do not select by default // do not select by default
selected = false; mSelected = false;
userIds = new ArrayList<String>(); userIds = new ArrayList<String>();
} }
public boolean isSelected() { public boolean isSelected() {
return selected; return mSelected;
} }
public void setSelected(boolean selected) { public void setSelected(boolean selected) {
this.selected = selected; this.mSelected = selected;
} }
/** /**
@ -147,13 +146,13 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
public ImportKeysListEntry(PGPKeyRing pgpKeyRing) { public ImportKeysListEntry(PGPKeyRing pgpKeyRing) {
// save actual key object into entry, used to import it later // save actual key object into entry, used to import it later
try { try {
this.bytes = pgpKeyRing.getEncoded(); this.mBytes = pgpKeyRing.getEncoded();
} catch (IOException e) { } catch (IOException e) {
Log.e(Constants.TAG, "IOException on pgpKeyRing.getEncoded()", e); Log.e(Constants.TAG, "IOException on pgpKeyRing.getEncoded()", e);
} }
// selected is default // selected is default
this.selected = true; this.mSelected = true;
if (pgpKeyRing instanceof PGPSecretKeyRing) { if (pgpKeyRing instanceof PGPSecretKeyRing) {
secretKey = true; secretKey = true;
@ -188,4 +187,4 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
this.algorithm = "unknown"; this.algorithm = "unknown";
} }
} }
} }

View File

@ -17,10 +17,8 @@
package org.sufficientlysecure.keychain.ui.adapter; package org.sufficientlysecure.keychain.ui.adapter;
import java.io.BufferedInputStream; import android.content.Context;
import java.io.InputStream; import android.support.v4.content.AsyncTaskLoader;
import java.util.ArrayList;
import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.PGPUtil;
@ -29,22 +27,26 @@ import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PositionAwareInputStream; import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
import android.content.Context; import java.io.BufferedInputStream;
import android.support.v4.content.AsyncTaskLoader; import java.io.InputStream;
import java.util.ArrayList;
public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { public class ImportKeysListLoader
extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
public static class FileHasNoContent extends Exception { public static class FileHasNoContent extends Exception {
} }
public static class NonPgpPart extends Exception { public static class NonPgpPart extends Exception {
private int count; private int mCount;
public NonPgpPart(int count) { public NonPgpPart(int count) {
this.count = count; this.mCount = count;
} }
public int getCount() { public int getCount() {
return count; return mCount;
} }
} }
@ -52,8 +54,8 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
InputData mInputData; InputData mInputData;
ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>(); ArrayList<ImportKeysListEntry> mData = new ArrayList<ImportKeysListEntry>();
AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper; AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper;
public ImportKeysListLoader(Context context, InputData inputData) { public ImportKeysListLoader(Context context, InputData inputData) {
super(context); super(context);
@ -64,16 +66,16 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
@Override @Override
public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() { public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(data, null); mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, null);
if (mInputData == null) { if (mInputData == null) {
Log.e(Constants.TAG, "Input data is null!"); Log.e(Constants.TAG, "Input data is null!");
return entryListWrapper; return mEntryListWrapper;
} }
generateListOfKeyrings(mInputData); generateListOfKeyrings(mInputData);
return entryListWrapper; return mEntryListWrapper;
} }
@Override @Override
@ -101,7 +103,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
/** /**
* Reads all PGPKeyRing objects from input * Reads all PGPKeyRing objects from input
* *
* @param inputData * @param inputData
* @return * @return
*/ */
@ -141,25 +143,25 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(Constants.TAG, "Exception on parsing key file!", e); Log.e(Constants.TAG, "Exception on parsing key file!", e);
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(data, e); mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, e);
nonPgpCounter = 0; nonPgpCounter = 0;
} }
if(isEmpty) { if (isEmpty) {
Log.e(Constants.TAG, "File has no content!", new FileHasNoContent()); Log.e(Constants.TAG, "File has no content!", new FileHasNoContent());
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>
(data, new FileHasNoContent()); (mData, new FileHasNoContent());
} }
if(nonPgpCounter > 0) { if (nonPgpCounter > 0) {
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>
(data, new NonPgpPart(nonPgpCounter)); (mData, new NonPgpPart(nonPgpCounter));
} }
} }
private void addToData(PGPKeyRing keyring) { private void addToData(PGPKeyRing keyring) {
ImportKeysListEntry item = new ImportKeysListEntry(keyring); ImportKeysListEntry item = new ImportKeysListEntry(keyring);
data.add(item); mData.add(item);
} }
} }

View File

@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui.adapter;
import android.content.Context; import android.content.Context;
import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.AsyncTaskLoader;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.HkpKeyServer; import org.sufficientlysecure.keychain.util.HkpKeyServer;
import org.sufficientlysecure.keychain.util.KeyServer; import org.sufficientlysecure.keychain.util.KeyServer;
@ -27,14 +26,15 @@ import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { public class ImportKeysListServerLoader
extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
Context mContext; Context mContext;
String mServerQuery; String mServerQuery;
String mKeyServer; String mKeyServer;
private ArrayList<ImportKeysListEntry> entryList = new ArrayList<ImportKeysListEntry>(); private ArrayList<ImportKeysListEntry> mEntryList = new ArrayList<ImportKeysListEntry>();
private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper; private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper;
public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) { public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) {
super(context); super(context);
@ -46,16 +46,16 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultW
@Override @Override
public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() { public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null); mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null);
if (mServerQuery == null) { if (mServerQuery == null) {
Log.e(Constants.TAG, "mServerQuery is null!"); Log.e(Constants.TAG, "mServerQuery is null!");
return entryListWrapper; return mEntryListWrapper;
} }
queryServer(mServerQuery, mKeyServer); queryServer(mServerQuery, mKeyServer);
return entryListWrapper; return mEntryListWrapper;
} }
@Override @Override
@ -89,18 +89,19 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultW
try { try {
ArrayList<ImportKeysListEntry> searchResult = server.search(query); ArrayList<ImportKeysListEntry> searchResult = server.search(query);
mEntryList.clear();
// add result to data // add result to data
entryList.addAll(searchResult); mEntryList.addAll(searchResult);
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null); mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null);
} catch (KeyServer.InsufficientQuery e) { } catch (KeyServer.InsufficientQuery e) {
Log.e(Constants.TAG, "InsufficientQuery", e); Log.e(Constants.TAG, "InsufficientQuery", e);
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e); mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
} catch (KeyServer.QueryException e) { } catch (KeyServer.QueryException e) {
Log.e(Constants.TAG, "QueryException", e); Log.e(Constants.TAG, "QueryException", e);
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e); mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
} catch (KeyServer.TooManyResponses e) { } catch (KeyServer.TooManyResponses e) {
Log.e(Constants.TAG, "TooManyResponses", e); Log.e(Constants.TAG, "TooManyResponses", e);
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e); mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
} }
} }

View File

@ -17,15 +17,11 @@
package org.sufficientlysecure.keychain.ui.adapter; package org.sufficientlysecure.keychain.ui.adapter;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import android.content.Context; import android.content.Context;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import java.util.*;
public class KeyValueSpinnerAdapter extends ArrayAdapter<String> { public class KeyValueSpinnerAdapter extends ArrayAdapter<String> {
private final HashMap<Integer, String> mData; private final HashMap<Integer, String> mData;
private final int[] mKeys; private final int[] mKeys;
@ -98,4 +94,4 @@ public class KeyValueSpinnerAdapter extends ArrayAdapter<String> {
} }
return -1; return -1;
} }
} }

View File

@ -17,12 +17,6 @@
package org.sufficientlysecure.keychain.ui.adapter; package org.sufficientlysecure.keychain.ui.adapter;
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;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -31,7 +25,11 @@ import android.view.ViewGroup;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; 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 { public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {
@ -46,11 +44,11 @@ public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {
private int mIndexProjectionValid; private int mIndexProjectionValid;
private int mIndexProjectionAvailable; private int mIndexProjectionAvailable;
public final static String PROJECTION_ROW_AVAILABLE = "available"; public static final String PROJECTION_ROW_AVAILABLE = "available";
public final static String PROJECTION_ROW_VALID = "valid"; public static final String PROJECTION_ROW_VALID = "valid";
public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView, public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView,
int keyType) { int keyType) {
super(context, c, flags); super(context, c, flags);
mInflater = LayoutInflater.from(context); mInflater = LayoutInflater.from(context);
@ -69,7 +67,7 @@ public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {
/** /**
* Get column indexes for performance reasons just once in constructor and swapCursor. For a * Get column indexes for performance reasons just once in constructor and swapCursor. For a
* performance comparison see http://stackoverflow.com/a/17999582 * performance comparison see http://stackoverflow.com/a/17999582
* *
* @param cursor * @param cursor
*/ */
private void initIndex(Cursor cursor) { private void initIndex(Cursor cursor) {

View File

@ -1,3 +1,20 @@
/*
* 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; package org.sufficientlysecure.keychain.ui.adapter;
import android.content.Context; import android.content.Context;
@ -19,12 +36,12 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo { static final class TabInfo {
private final Class<?> clss; private final Class<?> mClss;
private final Bundle args; private final Bundle mArgs;
TabInfo(Class<?> _class, Bundle _args) { TabInfo(Class<?> mClss, Bundle mArgs) {
clss = _class; this.mClss = mClss;
args = _args; this.mArgs = mArgs;
} }
} }
@ -54,7 +71,7 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.
@Override @Override
public Fragment getItem(int position) { public Fragment getItem(int position) {
TabInfo info = mTabs.get(position); TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args); return Fragment.instantiate(mContext, info.mClss.getName(), info.mArgs);
} }
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
@ -81,4 +98,4 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
} }
} }

View File

@ -17,10 +17,6 @@
package org.sufficientlysecure.keychain.ui.adapter; package org.sufficientlysecure.keychain.ui.adapter;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.support.v4.widget.CursorAdapter; import android.support.v4.widget.CursorAdapter;
@ -29,6 +25,9 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
public class ViewKeyKeysAdapter extends CursorAdapter { public class ViewKeyKeysAdapter extends CursorAdapter {
private LayoutInflater mInflater; private LayoutInflater mInflater;
@ -59,7 +58,7 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
/** /**
* Get column indexes for performance reasons just once in constructor and swapCursor. For a * Get column indexes for performance reasons just once in constructor and swapCursor. For a
* performance comparison see http://stackoverflow.com/a/17999582 * performance comparison see http://stackoverflow.com/a/17999582
* *
* @param cursor * @param cursor
*/ */
private void initIndex(Cursor cursor) { private void initIndex(Cursor cursor) {

View File

@ -17,9 +17,6 @@
package org.sufficientlysecure.keychain.ui.adapter; package org.sufficientlysecure.keychain.ui.adapter;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.support.v4.widget.CursorAdapter; import android.support.v4.widget.CursorAdapter;
@ -27,6 +24,8 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
public class ViewKeyUserIdsAdapter extends CursorAdapter { public class ViewKeyUserIdsAdapter extends CursorAdapter {
private LayoutInflater mInflater; private LayoutInflater mInflater;
@ -52,7 +51,7 @@ public class ViewKeyUserIdsAdapter extends CursorAdapter {
/** /**
* Get column indexes for performance reasons just once in constructor and swapCursor. For a * Get column indexes for performance reasons just once in constructor and swapCursor. For a
* performance comparison see http://stackoverflow.com/a/17999582 * performance comparison see http://stackoverflow.com/a/17999582
* *
* @param cursor * @param cursor
*/ */
private void initIndex(Cursor cursor) { private void initIndex(Cursor cursor) {

View File

@ -23,7 +23,6 @@ import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
public class BadImportKeyDialogFragment extends DialogFragment { public class BadImportKeyDialogFragment extends DialogFragment {

View File

@ -27,13 +27,11 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Spinner; import android.widget.Spinner;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Choice; import org.sufficientlysecure.keychain.util.Choice;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Vector;
public class CreateKeyDialogFragment extends DialogFragment { public class CreateKeyDialogFragment extends DialogFragment {
@ -150,4 +148,4 @@ public class CreateKeyDialogFragment extends DialogFragment {
return dialog.create(); return dialog.create();
} }
} }

View File

@ -17,10 +17,6 @@
package org.sufficientlysecure.keychain.ui.dialog; package org.sufficientlysecure.keychain.ui.dialog;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
@ -32,6 +28,9 @@ import android.os.Messenger;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.widget.Toast; 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 { public class DeleteFileDialogFragment extends DialogFragment {
private static final String ARG_DELETE_FILE = "delete_file"; private static final String ARG_DELETE_FILE = "delete_file";
@ -89,7 +88,8 @@ public class DeleteFileDialogFragment extends DialogFragment {
null); null);
// Message is received after deleting is done in ApgService // Message is received after deleting is done in ApgService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(activity, deletingDialog) { KeychainIntentServiceHandler saveHandler =
new KeychainIntentServiceHandler(activity, deletingDialog) {
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard ApgHandler first // handle messages by standard ApgHandler first
super.handleMessage(message); super.handleMessage(message);
@ -121,4 +121,4 @@ public class DeleteFileDialogFragment extends DialogFragment {
return alert.create(); return alert.create();
} }
} }

View File

@ -28,7 +28,6 @@ import android.os.Messenger;
import android.os.RemoteException; import android.os.RemoteException;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@ -118,8 +117,9 @@ public class DeleteKeyDialogFragment extends DialogFragment {
String selectionIDs = ""; String selectionIDs = "";
for (int i = 0; i < keyRingRowIds.length; i++) { for (int i = 0; i < keyRingRowIds.length; i++) {
selectionIDs += "'" + String.valueOf(keyRingRowIds[i]) + "'"; selectionIDs += "'" + String.valueOf(keyRingRowIds[i]) + "'";
if (i+1 < keyRingRowIds.length) if (i + 1 < keyRingRowIds.length) {
selectionIDs += ","; selectionIDs += ",";
}
} }
selection += selectionIDs + ")"; selection += selectionIDs + ")";
@ -140,7 +140,9 @@ public class DeleteKeyDialogFragment extends DialogFragment {
// check if a corresponding secret key exists... // check if a corresponding secret key exists...
Cursor secretCursor = activity.getContentResolver().query( Cursor secretCursor = activity.getContentResolver().query(
KeychainContract.KeyRings.buildSecretKeyRingsByMasterKeyIdUri(String.valueOf(masterKeyId)), KeychainContract.KeyRings
.buildSecretKeyRingsByMasterKeyIdUri(
String.valueOf(masterKeyId)),
null, null, null, null null, null, null, null
); );
if (secretCursor != null && secretCursor.getCount() > 0) { if (secretCursor != null && secretCursor.getCount() > 0) {
@ -205,4 +207,4 @@ public class DeleteKeyDialogFragment extends DialogFragment {
Log.w(Constants.TAG, "Messenger is null!", e); Log.w(Constants.TAG, "Messenger is null!", e);
} }
} }
} }

View File

@ -17,11 +17,6 @@
package org.sufficientlysecure.keychain.ui.dialog; package org.sufficientlysecure.keychain.ui.dialog;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
@ -38,8 +33,11 @@ import android.view.View;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton; 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 { public class FileDialogFragment extends DialogFragment {
private static final String ARG_MESSENGER = "messenger"; private static final String ARG_MESSENGER = "messenger";
@ -66,7 +64,7 @@ public class FileDialogFragment extends DialogFragment {
* Creates new instance of this file dialog fragment * Creates new instance of this file dialog fragment
*/ */
public static FileDialogFragment newInstance(Messenger messenger, String title, String message, public static FileDialogFragment newInstance(Messenger messenger, String title, String message,
String defaultFile, String checkboxText) { String defaultFile, String checkboxText) {
FileDialogFragment frag = new FileDialogFragment(); FileDialogFragment frag = new FileDialogFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putParcelable(ARG_MESSENGER, messenger); args.putParcelable(ARG_MESSENGER, messenger);
@ -176,34 +174,33 @@ public class FileDialogFragment extends DialogFragment {
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode & 0xFFFF) { switch (requestCode & 0xFFFF) {
case REQUEST_CODE: { case REQUEST_CODE: {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
try { try {
String path = data.getData().getPath(); String path = data.getData().getPath();
Log.d(Constants.TAG, "path=" + path); Log.d(Constants.TAG, "path=" + path);
// set filename used in export/import dialogs // set filename used in export/import dialogs
setFilename(path); setFilename(path);
} catch (NullPointerException e) { } catch (NullPointerException e) {
Log.e(Constants.TAG, "Nullpointer while retrieving path!", e); Log.e(Constants.TAG, "Nullpointer while retrieving path!", e);
}
} }
break;
} }
break; default:
} super.onActivityResult(requestCode, resultCode, data);
default: break;
super.onActivityResult(requestCode, resultCode, data);
break;
} }
} }
/** /**
* Send message back to handler which is initialized in a activity * Send message back to handler which is initialized in a activity
* *
* @param what * @param what Message integer you want to send
* Message integer you want to send
*/ */
private void sendMessageToHandler(Integer what, Bundle data) { private void sendMessageToHandler(Integer what, Bundle data) {
Message msg = Message.obtain(); Message msg = Message.obtain();

View File

@ -17,20 +17,6 @@
package org.sufficientlysecure.keychain.ui.dialog; package org.sufficientlysecure.keychain.ui.dialog;
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;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
@ -52,6 +38,19 @@ import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener; import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast; 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 { public class PassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
private static final String ARG_MESSENGER = "messenger"; private static final String ARG_MESSENGER = "messenger";
@ -62,20 +61,18 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
private Messenger mMessenger; private Messenger mMessenger;
private EditText mPassphraseEditText; private EditText mPassphraseEditText;
private boolean canKB; private boolean mCanKB;
/** /**
* Creates new instance of this dialog fragment * Creates new instance of this dialog fragment
* *
* @param secretKeyId * @param secretKeyId secret key id you want to use
* secret key id you want to use * @param messenger to communicate back after caching the passphrase
* @param messenger
* to communicate back after caching the passphrase
* @return * @return
* @throws PgpGeneralException * @throws PgpGeneralException
*/ */
public static PassphraseDialogFragment newInstance(Context context, Messenger messenger, public static PassphraseDialogFragment newInstance(Context context, Messenger messenger,
long secretKeyId) throws PgpGeneralException { long secretKeyId) throws PgpGeneralException {
// check if secret key has a passphrase // check if secret key has a passphrase
if (!(secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none)) { if (!(secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none)) {
if (!PassphraseCacheService.hasPassphrase(context, secretKeyId)) { if (!PassphraseCacheService.hasPassphrase(context, secretKeyId)) {
@ -131,7 +128,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
} }
}); });
alert.setCancelable(false); alert.setCancelable(false);
canKB = false; mCanKB = false;
return alert.create(); return alert.create();
} }
String userId = PgpKeyHelper.getMainUserIdSafe(activity, secretKey); String userId = PgpKeyHelper.getMainUserIdSafe(activity, secretKey);
@ -171,7 +168,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
Toast.makeText(activity, Toast.makeText(activity,
R.string.error_could_not_extract_private_key, R.string.error_could_not_extract_private_key,
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
sendMessageToHandler(MESSAGE_CANCEL); sendMessageToHandler(MESSAGE_CANCEL);
return; return;
} else { } else {
@ -187,14 +184,14 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
} catch (PGPException e) { } catch (PGPException e) {
Toast.makeText(activity, R.string.wrong_passphrase, Toast.makeText(activity, R.string.wrong_passphrase,
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
sendMessageToHandler(MESSAGE_CANCEL); sendMessageToHandler(MESSAGE_CANCEL);
return; return;
} }
} else { } else {
Toast.makeText(activity, R.string.error_could_not_extract_private_key, Toast.makeText(activity, R.string.error_could_not_extract_private_key,
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
sendMessageToHandler(MESSAGE_CANCEL); sendMessageToHandler(MESSAGE_CANCEL);
return; // ran out of keys to try return; // ran out of keys to try
} }
@ -207,7 +204,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
// cache the new passphrase // cache the new passphrase
Log.d(Constants.TAG, "Everything okay! Caching entered passphrase"); Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
PassphraseCacheService.addCachedPassphrase(activity, keyId, passphrase); PassphraseCacheService.addCachedPassphrase(activity, keyId, passphrase);
if ( !keyOK && clickSecretKey.getKeyID() != keyId) { if (!keyOK && clickSecretKey.getKeyID() != keyId) {
PassphraseCacheService.addCachedPassphrase(activity, clickSecretKey.getKeyID(), PassphraseCacheService.addCachedPassphrase(activity, clickSecretKey.getKeyID(),
passphrase); passphrase);
} }
@ -224,14 +221,14 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
} }
}); });
canKB = true; mCanKB = true;
return alert.create(); return alert.create();
} }
@Override @Override
public void onActivityCreated(Bundle arg0) { public void onActivityCreated(Bundle arg0) {
super.onActivityCreated(arg0); super.onActivityCreated(arg0);
if (canKB) { if (mCanKB) {
// request focus and open soft keyboard // request focus and open soft keyboard
mPassphraseEditText.requestFocus(); mPassphraseEditText.requestFocus();
getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE); getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
@ -265,9 +262,8 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
/** /**
* Send message back to handler which is initialized in a activity * Send message back to handler which is initialized in a activity
* *
* @param what * @param what Message integer you want to send
* Message integer you want to send
*/ */
private void sendMessageToHandler(Integer what) { private void sendMessageToHandler(Integer what) {
Message msg = Message.obtain(); Message msg = Message.obtain();

View File

@ -26,7 +26,6 @@ import android.content.DialogInterface.OnKeyListener;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.view.KeyEvent; import android.view.KeyEvent;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
public class ProgressDialogFragment extends DialogFragment { public class ProgressDialogFragment extends DialogFragment {
@ -101,8 +100,9 @@ public class ProgressDialogFragment extends DialogFragment {
public void onCancel(DialogInterface dialog) { public void onCancel(DialogInterface dialog) {
super.onCancel(dialog); super.onCancel(dialog);
if (this.mOnCancelListener != null) if (this.mOnCancelListener != null) {
this.mOnCancelListener.onCancel(dialog); this.mOnCancelListener.onCancel(dialog);
}
} }
/** /**
@ -151,4 +151,4 @@ public class ProgressDialogFragment extends DialogFragment {
return dialog; return dialog;
} }
} }

View File

@ -17,10 +17,6 @@
package org.sufficientlysecure.keychain.ui.dialog; package org.sufficientlysecure.keychain.ui.dialog;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
@ -40,6 +36,9 @@ import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener; import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast; 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 { public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
private static final String ARG_MESSENGER = "messenger"; private static final String ARG_MESSENGER = "messenger";
@ -55,11 +54,9 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
/** /**
* Creates new instance of this dialog fragment * Creates new instance of this dialog fragment
* *
* @param title * @param title title of dialog
* title of dialog * @param messenger to communicate back after setting the passphrase
* @param messenger
* to communicate back after setting the passphrase
* @return * @return
*/ */
public static SetPassphraseDialogFragment newInstance(Messenger messenger, int title) { public static SetPassphraseDialogFragment newInstance(Messenger messenger, int title) {
@ -96,7 +93,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again); mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again);
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
dismiss(); dismiss();
@ -130,7 +127,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
}); });
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
dismiss(); dismiss();
@ -168,9 +165,8 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
/** /**
* Send message back to handler which is initialized in a activity * Send message back to handler which is initialized in a activity
* *
* @param what * @param what Message integer you want to send
* Message integer you want to send
*/ */
private void sendMessageToHandler(Integer what, Bundle data) { private void sendMessageToHandler(Integer what, Bundle data) {
Message msg = Message.obtain(); Message msg = Message.obtain();
@ -187,4 +183,4 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
Log.w(Constants.TAG, "Messenger is null!", e); Log.w(Constants.TAG, "Messenger is null!", e);
} }
} }
} }

View File

@ -17,9 +17,6 @@
package org.sufficientlysecure.keychain.ui.dialog; package org.sufficientlysecure.keychain.ui.dialog;
import org.sufficientlysecure.htmltextview.HtmlTextView;
import org.sufficientlysecure.keychain.R;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
@ -31,6 +28,8 @@ import android.os.Bundle;
import android.provider.Settings; import android.provider.Settings;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import org.sufficientlysecure.htmltextview.HtmlTextView;
import org.sufficientlysecure.keychain.R;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class ShareNfcDialogFragment extends DialogFragment { public class ShareNfcDialogFragment extends DialogFragment {
@ -97,4 +96,4 @@ public class ShareNfcDialogFragment extends DialogFragment {
return alert.create(); return alert.create();
} }
} }

View File

@ -28,7 +28,6 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;

View File

@ -24,7 +24,7 @@ import android.widget.ListView;
/** /**
* Automatically calculate height of ListView based on contained items. This enables to put this * Automatically calculate height of ListView based on contained items. This enables to put this
* ListView into a ScrollView without messing up. * ListView into a ScrollView without messing up.
* * <p/>
* from * from
* http://stackoverflow.com/questions/2419246/how-do-i-create-a-listview-thats-not-in-a-scrollview- * http://stackoverflow.com/questions/2419246/how-do-i-create-a-listview-thats-not-in-a-scrollview-
* or-has-the-scrollview-dis * or-has-the-scrollview-dis
@ -52,4 +52,4 @@ public class FixedListView extends ListView {
super.onMeasure(widthMeasureSpec, expandSpec); super.onMeasure(widthMeasureSpec, expandSpec);
} }
} }

View File

@ -25,7 +25,7 @@ import android.util.AttributeSet;
* values should use {@link android.content.SharedPreferences#getInt}. When using XML-declared * 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 * arrays for entry values, the arrays should be regular string arrays containing valid integer
* values. * values.
* *
* @author Rodrigo Damazio * @author Rodrigo Damazio
*/ */
public class IntegerListPreference extends ListPreference { public class IntegerListPreference extends ListPreference {

View File

@ -16,20 +16,7 @@
package org.sufficientlysecure.keychain.ui.widget; package org.sufficientlysecure.keychain.ui.widget;
import java.text.DateFormat; import android.annotation.TargetApi;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.Vector;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKey;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.Choice;
import android.app.DatePickerDialog; import android.app.DatePickerDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
@ -39,13 +26,17 @@ import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.*;
import android.widget.DatePicker;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKey;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.Choice;
import java.text.DateFormat;
import java.util.*;
public class KeyEditor extends LinearLayout implements Editor, OnClickListener { public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
private PGPSecretKey mKey; private PGPSecretKey mKey;
@ -63,7 +54,8 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
GregorianCalendar mExpiryDate; GregorianCalendar mExpiryDate;
private int mDatePickerResultCount = 0; private int mDatePickerResultCount = 0;
private DatePickerDialog.OnDateSetListener mExpiryDateSetListener = new DatePickerDialog.OnDateSetListener() { private DatePickerDialog.OnDateSetListener mExpiryDateSetListener =
new DatePickerDialog.OnDateSetListener() {
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
// Note: Ignore results after the first one - android sends multiples. // Note: Ignore results after the first one - android sends multiples.
if (mDatePickerResultCount++ == 0) { if (mDatePickerResultCount++ == 0) {
@ -110,6 +102,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
setExpiryDate(null); setExpiryDate(null);
mExpiryDateButton.setOnClickListener(new OnClickListener() { mExpiryDateButton.setOnClickListener(new OnClickListener() {
@TargetApi(11)
public void onClick(View v) { public void onClick(View v) {
GregorianCalendar date = mExpiryDate; GregorianCalendar date = mExpiryDate;
if (date == null) { if (date == null) {
@ -137,16 +130,18 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
}); });
// setCalendarViewShown() is supported from API 11 onwards. // setCalendarViewShown() is supported from API 11 onwards.
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
// Hide calendarView in tablets because of the unix warparound bug. // Hide calendarView in tablets because of the unix warparound bug.
dialog.getDatePicker().setCalendarViewShown(false); dialog.getDatePicker().setCalendarViewShown(false);
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
if ( dialog != null && mCreatedDate != null ) { if (dialog != null && mCreatedDate != null) {
dialog.getDatePicker().setMinDate(mCreatedDate.getTime().getTime()+ DateUtils.DAY_IN_MILLIS); dialog.getDatePicker()
.setMinDate(
mCreatedDate.getTime().getTime() + DateUtils.DAY_IN_MILLIS);
} else { } else {
//When created date isn't available //When created date isn't available
dialog.getDatePicker().setMinDate(date.getTime().getTime()+ DateUtils.DAY_IN_MILLIS); dialog.getDatePicker().setMinDate(date.getTime().getTime() + DateUtils.DAY_IN_MILLIS);
} }
} }
@ -285,9 +280,11 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
class ExpiryDatePickerDialog extends DatePickerDialog { class ExpiryDatePickerDialog extends DatePickerDialog {
public ExpiryDatePickerDialog(Context context, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) { public ExpiryDatePickerDialog(Context context, OnDateSetListener callBack,
int year, int monthOfYear, int dayOfMonth) {
super(context, callBack, year, monthOfYear, dayOfMonth); super(context, callBack, year, monthOfYear, dayOfMonth);
} }
//Set permanent title. //Set permanent title.
public void setTitle(CharSequence title) { public void setTitle(CharSequence title) {
super.setTitle(getContext().getString(R.string.expiry_date_dialog_title)); super.setTitle(getContext().getString(R.string.expiry_date_dialog_title));

View File

@ -16,8 +16,6 @@
package org.sufficientlysecure.keychain.ui.widget; package org.sufficientlysecure.keychain.ui.widget;
import org.sufficientlysecure.keychain.R;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
@ -25,8 +23,8 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.R;
public class KeyServerEditor extends LinearLayout implements Editor, OnClickListener { public class KeyServerEditor extends LinearLayout implements Editor, OnClickListener {
private EditorListener mEditorListener = null; private EditorListener mEditorListener = null;

View File

@ -31,9 +31,7 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@ -57,7 +55,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
private Choice mNewKeyAlgorithmChoice; private Choice mNewKeyAlgorithmChoice;
private int mNewKeySize; private int mNewKeySize;
private boolean canEdit = true; private boolean mCanEdit = true;
private ActionBarActivity mActivity; private ActionBarActivity mActivity;
@ -97,8 +95,8 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
} }
public void setCanEdit(boolean bCanEdit) { public void setCanEdit(boolean bCanEdit) {
canEdit = bCanEdit; mCanEdit = bCanEdit;
if (!canEdit) { if (!mCanEdit) {
mPlusButton.setVisibility(View.INVISIBLE); mPlusButton.setVisibility(View.INVISIBLE);
} }
} }
@ -139,7 +137,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
* {@inheritDoc} * {@inheritDoc}
*/ */
public void onClick(View v) { public void onClick(View v) {
if (canEdit) { if (mCanEdit) {
switch (mType) { switch (mType) {
case Id.type.user_id: { case Id.type.user_id: {
UserIdEditor view = (UserIdEditor) mInflater.inflate( UserIdEditor view = (UserIdEditor) mInflater.inflate(
@ -153,15 +151,18 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
} }
case Id.type.key: { case Id.type.key: {
CreateKeyDialogFragment mCreateKeyDialogFragment = CreateKeyDialogFragment.newInstance(mEditors.getChildCount()); CreateKeyDialogFragment mCreateKeyDialogFragment =
mCreateKeyDialogFragment.setOnAlgorithmSelectedListener(new CreateKeyDialogFragment.OnAlgorithmSelectedListener() { CreateKeyDialogFragment.newInstance(mEditors.getChildCount());
@Override mCreateKeyDialogFragment
public void onAlgorithmSelected(Choice algorithmChoice, int keySize) { .setOnAlgorithmSelectedListener(
mNewKeyAlgorithmChoice = algorithmChoice; new CreateKeyDialogFragment.OnAlgorithmSelectedListener() {
mNewKeySize = keySize; @Override
createKey(); public void onAlgorithmSelected(Choice algorithmChoice, int keySize) {
} mNewKeyAlgorithmChoice = algorithmChoice;
}); mNewKeySize = keySize;
createKey();
}
});
mCreateKeyDialogFragment.show(mActivity.getSupportFragmentManager(), "createKeyDialog"); mCreateKeyDialogFragment.show(mActivity.getSupportFragmentManager(), "createKeyDialog");
break; break;
} }
@ -188,7 +189,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
if (mEditors.getChildCount() == 0) { if (mEditors.getChildCount() == 0) {
view.setIsMainUserId(true); view.setIsMainUserId(true);
} }
view.setCanEdit(canEdit); view.setCanEdit(mCanEdit);
mEditors.addView(view); mEditors.addView(view);
} }
@ -209,7 +210,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
view.setEditorListener(this); view.setEditorListener(this);
boolean isMasterKey = (mEditors.getChildCount() == 0); boolean isMasterKey = (mEditors.getChildCount() == 0);
view.setValue(list.get(i), isMasterKey, usages.get(i)); view.setValue(list.get(i), isMasterKey, usages.get(i));
view.setCanEdit(canEdit); view.setCanEdit(mCanEdit);
mEditors.addView(view); mEditors.addView(view);
} }

View File

@ -26,7 +26,7 @@ import android.widget.TextView;
/** /**
* Copied from StickyListHeaders lib example * Copied from StickyListHeaders lib example
* *
* @author Eric Frohnhoefer * @author Eric Frohnhoefer
*/ */
public class UnderlineTextView extends TextView { public class UnderlineTextView extends TextView {

View File

@ -16,21 +16,22 @@
package org.sufficientlysecure.keychain.ui.widget; package org.sufficientlysecure.keychain.ui.widget;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.widget.*;
import org.sufficientlysecure.keychain.R;
import android.content.Context; import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Patterns;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.*;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ContactHelper; import org.sufficientlysecure.keychain.helper.ContactHelper;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class UserIdEditor extends LinearLayout implements Editor, OnClickListener { public class UserIdEditor extends LinearLayout implements Editor, OnClickListener {
private EditorListener mEditorListener = null; private EditorListener mEditorListener = null;
@ -40,14 +41,6 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
private AutoCompleteTextView mEmail; private AutoCompleteTextView mEmail;
private EditText mComment; private EditText mComment;
// see http://www.regular-expressions.info/email.html
// RFC 2822 if we omit the syntax using double quotes and square brackets
// android.util.Patterns.EMAIL_ADDRESS is only available as of Android 2.2+
private static final Pattern EMAIL_PATTERN = Pattern
.compile(
"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
Pattern.CASE_INSENSITIVE);
public static class NoNameException extends Exception { public static class NoNameException extends Exception {
static final long serialVersionUID = 0xf812773343L; static final long serialVersionUID = 0xf812773343L;
@ -109,8 +102,33 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
mEmail.setAdapter( mEmail.setAdapter(
new ArrayAdapter<String> new ArrayAdapter<String>
(this.getContext(), android.R.layout.simple_dropdown_item_1line, (this.getContext(), android.R.layout.simple_dropdown_item_1line,
ContactHelper.getMailAccounts(getContext()) 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);
}
}
});
super.onFinishInflate(); super.onFinishInflate();
} }
@ -138,19 +156,11 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
} }
} }
public String getValue() throws NoNameException, NoEmailException, InvalidEmailException { public String getValue() throws NoNameException, NoEmailException {
String name = ("" + mName.getText()).trim(); String name = ("" + mName.getText()).trim();
String email = ("" + mEmail.getText()).trim(); String email = ("" + mEmail.getText()).trim();
String comment = ("" + mComment.getText()).trim(); String comment = ("" + mComment.getText()).trim();
if (email.length() > 0) {
Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
if (!emailMatcher.matches()) {
throw new InvalidEmailException(getContext().getString(R.string.error_invalid_email,
email));
}
}
String userId = name; String userId = name;
if (comment.length() > 0) { if (comment.length() > 0) {
userId += " (" + comment + ")"; userId += " (" + comment + ")";

View File

@ -17,13 +17,14 @@
package org.sufficientlysecure.keychain.util; package org.sufficientlysecure.keychain.util;
import java.util.HashMap; import android.annotation.SuppressLint;
import android.app.Activity;
import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData; import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import android.annotation.SuppressLint;
import android.app.Activity; import java.util.HashMap;
@SuppressLint("UseSparseArrays") @SuppressLint("UseSparseArrays")
public class AlgorithmNames { public class AlgorithmNames {

Some files were not shown because too many files have changed in this diff Show More