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
[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:
# Install base Android SDK
- 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
- tar xzf android-sdk_r22.3-linux.tgz
- export ANDROID_HOME=$PWD/android-sdk-linux

View File

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

View File

@ -16,10 +16,10 @@
package org.sufficientlysecure.keychain;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import android.os.Environment;
import org.spongycastle.jce.provider.BouncyCastleProvider;
public final class Constants {
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 class path {
public static final class Path {
public static final String APP_DIR = Environment.getExternalStorageDirectory()
+ "/OpenPGP-Keychain";
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 class pref {
public static final class Pref {
public static final String DEFAULT_ENCRYPTION_ALGORITHM = "defaultEncryptionAlgorithm";
public static final String DEFAULT_HASH_ALGORITHM = "defaultHashAlgorithm";
public static final String DEFAULT_ASCII_ARMOUR = "defaultAsciiArmour";
@ -59,7 +59,7 @@ public final class Constants {
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";
}

View File

@ -64,7 +64,7 @@ public class KeychainApplication extends Application {
// Create APG directory on sdcard if not existing
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()) {
// ignore this for now, it's not crucial
// that the directory doesn't exist at this point

View File

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

View File

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

View File

@ -16,6 +16,16 @@
package org.sufficientlysecure.keychain.helper;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.support.v7.app.ActionBarActivity;
import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
@ -26,25 +36,15 @@ import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
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 {
protected FileDialogFragment mFileDialog;
protected String mExportFilename;
ActionBarActivity activity;
ActionBarActivity mActivity;
public ExportHelper(ActionBarActivity activity) {
super();
this.activity = activity;
this.mActivity = activity;
}
public void deleteKey(Uri dataUri, final int keyType, Handler deleteHandler) {
@ -54,16 +54,16 @@ public class ExportHelper {
Messenger messenger = new Messenger(deleteHandler);
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
*/
public void showExportKeysDialog(final long[] rowIds, final int keyType,
final String exportFilename) {
final String exportFilename) {
mExportFilename = exportFilename;
// Message is received after file is selected
@ -87,23 +87,23 @@ public class ExportHelper {
String title = null;
if (rowIds == null) {
// export all keys
title = activity.getString(R.string.title_export_keys);
title = mActivity.getString(R.string.title_export_keys);
} else {
// 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;
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 {
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,
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");
// 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);
@ -134,8 +134,16 @@ public class ExportHelper {
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
// Message is received after exporting is done in ApgService
KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(activity,
activity.getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) {
KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(mActivity,
mActivity.getString(R.string.progress_exporting),
ProgressDialog.STYLE_HORIZONTAL,
true,
new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
mActivity.stopService(intent);
}
}) {
public void handleMessage(Message message) {
// handle messages by standard ApgHandler first
super.handleMessage(message);
@ -147,13 +155,13 @@ public class ExportHelper {
int exported = returnData.getInt(KeychainIntentService.RESULT_EXPORT);
String toastMessage;
if (exported == 1) {
toastMessage = activity.getString(R.string.key_exported);
toastMessage = mActivity.getString(R.string.key_exported);
} else if (exported > 0) {
toastMessage = activity.getString(R.string.keys_exported, exported);
toastMessage = mActivity.getString(R.string.keys_exported, exported);
} 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);
// show progress dialog
exportHandler.showProgressDialog(activity);
exportHandler.showProgressDialog(mActivity);
// start service with intent
activity.startService(intent);
mActivity.startService(intent);
}
}

View File

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

View File

@ -17,19 +17,21 @@
package org.sufficientlysecure.keychain.helper;
import java.util.Iterator;
import java.util.Set;
import android.os.Bundle;
import org.sufficientlysecure.keychain.Constants;
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 {
/**
* Logs bundle content to debug for inspecting the content
*
*
* @param bundle
* @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;
import android.content.Context;
import android.content.SharedPreferences;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import android.content.Context;
import android.content.SharedPreferences;
import java.util.Vector;
/**
@ -38,8 +37,8 @@ public class Preferences {
return getPreferences(context, false);
}
public static synchronized Preferences getPreferences(Context context, boolean force_new) {
if (mPreferences == null || force_new) {
public static synchronized Preferences getPreferences(Context context, boolean forceNew) {
if (mPreferences == null || forceNew) {
mPreferences = new Preferences(context);
}
return mPreferences;
@ -50,17 +49,17 @@ public class Preferences {
}
public String getLanguage() {
return mSharedPreferences.getString(Constants.pref.LANGUAGE, "");
return mSharedPreferences.getString(Constants.Pref.LANGUAGE, "");
}
public void setLanguage(String value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(Constants.pref.LANGUAGE, value);
editor.putString(Constants.Pref.LANGUAGE, value);
editor.commit();
}
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
// supported
if (ttl == 0) {
@ -71,77 +70,77 @@ public class Preferences {
public void setPassPhraseCacheTtl(int value) {
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();
}
public int getDefaultEncryptionAlgorithm() {
return mSharedPreferences.getInt(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM,
return mSharedPreferences.getInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM,
PGPEncryptedData.AES_256);
}
public void setDefaultEncryptionAlgorithm(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM, value);
editor.putInt(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM, value);
editor.commit();
}
public int getDefaultHashAlgorithm() {
return mSharedPreferences.getInt(Constants.pref.DEFAULT_HASH_ALGORITHM,
return mSharedPreferences.getInt(Constants.Pref.DEFAULT_HASH_ALGORITHM,
HashAlgorithmTags.SHA512);
}
public void setDefaultHashAlgorithm(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(Constants.pref.DEFAULT_HASH_ALGORITHM, value);
editor.putInt(Constants.Pref.DEFAULT_HASH_ALGORITHM, value);
editor.commit();
}
public int getDefaultMessageCompression() {
return mSharedPreferences.getInt(Constants.pref.DEFAULT_MESSAGE_COMPRESSION,
return mSharedPreferences.getInt(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION,
Id.choice.compression.zlib);
}
public void setDefaultMessageCompression(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(Constants.pref.DEFAULT_MESSAGE_COMPRESSION, value);
editor.putInt(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION, value);
editor.commit();
}
public int getDefaultFileCompression() {
return mSharedPreferences.getInt(Constants.pref.DEFAULT_FILE_COMPRESSION,
return mSharedPreferences.getInt(Constants.Pref.DEFAULT_FILE_COMPRESSION,
Id.choice.compression.none);
}
public void setDefaultFileCompression(int value) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putInt(Constants.pref.DEFAULT_FILE_COMPRESSION, value);
editor.putInt(Constants.Pref.DEFAULT_FILE_COMPRESSION, value);
editor.commit();
}
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) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putBoolean(Constants.pref.DEFAULT_ASCII_ARMOUR, value);
editor.putBoolean(Constants.Pref.DEFAULT_ASCII_ARMOUR, value);
editor.commit();
}
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) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putBoolean(Constants.pref.FORCE_V3_SIGNATURES, value);
editor.putBoolean(Constants.Pref.FORCE_V3_SIGNATURES, value);
editor.commit();
}
public String[] getKeyServers() {
String rawData = mSharedPreferences.getString(Constants.pref.KEY_SERVERS,
Constants.defaults.KEY_SERVERS);
String rawData = mSharedPreferences.getString(Constants.Pref.KEY_SERVERS,
Constants.Defaults.KEY_SERVERS);
Vector<String> servers = new Vector<String>();
String chunks[] = rawData.split(",");
for (String c : chunks) {
@ -166,7 +165,7 @@ public class Preferences {
}
rawData += tmp;
}
editor.putString(Constants.pref.KEY_SERVERS, rawData);
editor.putString(Constants.Pref.KEY_SERVERS, rawData);
editor.commit();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,21 +17,9 @@
package org.sufficientlysecure.keychain.pgp;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.Context;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.*;
import org.spongycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Constants;
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.Log;
import android.content.Context;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PgpKeyHelper {

View File

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

View File

@ -18,28 +18,11 @@
package org.sufficientlysecure.keychain.pgp;
import android.content.Context;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.BCPGOutputStream;
import org.spongycastle.openpgp.PGPCompressedDataGenerator;
import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPLiteralData;
import org.spongycastle.openpgp.PGPLiteralDataGenerator;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.spongycastle.openpgp.PGPV3SignatureGenerator;
import org.spongycastle.openpgp.*;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.spongycastle.openpgp.operator.jcajce.*;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
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.ProgressDialogUpdater;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.*;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
@ -63,110 +42,110 @@ import java.util.Date;
* This class uses a Builder pattern!
*/
public class PgpSignEncrypt {
private Context context;
private InputData data;
private OutputStream outStream;
private Context mContext;
private InputData mData;
private OutputStream mOutStream;
private ProgressDialogUpdater progress;
private boolean enableAsciiArmorOutput;
private int compressionId;
private long[] encryptionKeyIds;
private String encryptionPassphrase;
private int symmetricEncryptionAlgorithm;
private long signatureKeyId;
private int signatureHashAlgorithm;
private boolean signatureForceV3;
private String signaturePassphrase;
private ProgressDialogUpdater mProgress;
private boolean mEnableAsciiArmorOutput;
private int mCompressionId;
private long[] mEncryptionKeyIds;
private String mEncryptionPassphrase;
private int mSymmetricEncryptionAlgorithm;
private long mSignatureKeyId;
private int mSignatureHashAlgorithm;
private boolean mSignatureForceV3;
private String mSignaturePassphrase;
private PgpSignEncrypt(Builder builder) {
// private Constructor can only be called from Builder
this.context = builder.context;
this.data = builder.data;
this.outStream = builder.outStream;
this.mContext = builder.mContext;
this.mData = builder.mData;
this.mOutStream = builder.mOutStream;
this.progress = builder.progress;
this.enableAsciiArmorOutput = builder.enableAsciiArmorOutput;
this.compressionId = builder.compressionId;
this.encryptionKeyIds = builder.encryptionKeyIds;
this.encryptionPassphrase = builder.encryptionPassphrase;
this.symmetricEncryptionAlgorithm = builder.symmetricEncryptionAlgorithm;
this.signatureKeyId = builder.signatureKeyId;
this.signatureHashAlgorithm = builder.signatureHashAlgorithm;
this.signatureForceV3 = builder.signatureForceV3;
this.signaturePassphrase = builder.signaturePassphrase;
this.mProgress = builder.mProgress;
this.mEnableAsciiArmorOutput = builder.mEnableAsciiArmorOutput;
this.mCompressionId = builder.mCompressionId;
this.mEncryptionKeyIds = builder.mEncryptionKeyIds;
this.mEncryptionPassphrase = builder.mEncryptionPassphrase;
this.mSymmetricEncryptionAlgorithm = builder.mSymmetricEncryptionAlgorithm;
this.mSignatureKeyId = builder.mSignatureKeyId;
this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm;
this.mSignatureForceV3 = builder.mSignatureForceV3;
this.mSignaturePassphrase = builder.mSignaturePassphrase;
}
public static class Builder {
// mandatory parameter
private Context context;
private InputData data;
private OutputStream outStream;
private Context mContext;
private InputData mData;
private OutputStream mOutStream;
// optional
private ProgressDialogUpdater progress = null;
private boolean enableAsciiArmorOutput = false;
private int compressionId = Id.choice.compression.none;
private long[] encryptionKeyIds = new long[0];
private String encryptionPassphrase = null;
private int symmetricEncryptionAlgorithm = 0;
private long signatureKeyId = Id.key.none;
private int signatureHashAlgorithm = 0;
private boolean signatureForceV3 = false;
private String signaturePassphrase = null;
private ProgressDialogUpdater mProgress = null;
private boolean mEnableAsciiArmorOutput = false;
private int mCompressionId = Id.choice.compression.none;
private long[] mEncryptionKeyIds = new long[0];
private String mEncryptionPassphrase = null;
private int mSymmetricEncryptionAlgorithm = 0;
private long mSignatureKeyId = Id.key.none;
private int mSignatureHashAlgorithm = 0;
private boolean mSignatureForceV3 = false;
private String mSignaturePassphrase = null;
public Builder(Context context, InputData data, OutputStream outStream) {
this.context = context;
this.data = data;
this.outStream = outStream;
this.mContext = context;
this.mData = data;
this.mOutStream = outStream;
}
public Builder progress(ProgressDialogUpdater progress) {
this.progress = progress;
this.mProgress = progress;
return this;
}
public Builder enableAsciiArmorOutput(boolean enableAsciiArmorOutput) {
this.enableAsciiArmorOutput = enableAsciiArmorOutput;
this.mEnableAsciiArmorOutput = enableAsciiArmorOutput;
return this;
}
public Builder compressionId(int compressionId) {
this.compressionId = compressionId;
this.mCompressionId = compressionId;
return this;
}
public Builder encryptionKeyIds(long[] encryptionKeyIds) {
this.encryptionKeyIds = encryptionKeyIds;
this.mEncryptionKeyIds = encryptionKeyIds;
return this;
}
public Builder encryptionPassphrase(String encryptionPassphrase) {
this.encryptionPassphrase = encryptionPassphrase;
this.mEncryptionPassphrase = encryptionPassphrase;
return this;
}
public Builder symmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) {
this.symmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
this.mSymmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
return this;
}
public Builder signatureKeyId(long signatureKeyId) {
this.signatureKeyId = signatureKeyId;
this.mSignatureKeyId = signatureKeyId;
return this;
}
public Builder signatureHashAlgorithm(int signatureHashAlgorithm) {
this.signatureHashAlgorithm = signatureHashAlgorithm;
this.mSignatureHashAlgorithm = signatureHashAlgorithm;
return this;
}
public Builder signatureForceV3(boolean signatureForceV3) {
this.signatureForceV3 = signatureForceV3;
this.mSignatureForceV3 = signatureForceV3;
return this;
}
public Builder signaturePassphrase(String signaturePassphrase) {
this.signaturePassphrase = signaturePassphrase;
this.mSignaturePassphrase = signaturePassphrase;
return this;
}
@ -176,14 +155,14 @@ public class PgpSignEncrypt {
}
public void updateProgress(int message, int current, int total) {
if (progress != null) {
progress.setProgress(message, current, total);
if (mProgress != null) {
mProgress.setProgress(message, current, total);
}
}
public void updateProgress(int current, int total) {
if (progress != null) {
progress.setProgress(current, total);
if (mProgress != null) {
mProgress.setProgress(current, total);
}
}
@ -201,17 +180,17 @@ public class PgpSignEncrypt {
throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
NoSuchAlgorithmException, SignatureException {
boolean enableSignature = signatureKeyId != Id.key.none;
boolean enableEncryption = (encryptionKeyIds.length != 0 || encryptionPassphrase != null);
boolean enableCompression = (enableEncryption && compressionId != Id.choice.compression.none);
boolean enableSignature = mSignatureKeyId != Id.key.none;
boolean enableEncryption = (mEncryptionKeyIds.length != 0 || mEncryptionPassphrase != null);
boolean enableCompression = (enableEncryption && mCompressionId != Id.choice.compression.none);
Log.d(Constants.TAG, "enableSignature:" + enableSignature
+ "\nenableEncryption:" + enableEncryption
+ "\nenableCompression:" + enableCompression
+ "\nenableAsciiArmorOutput:" + enableAsciiArmorOutput);
+ "\nenableAsciiArmorOutput:" + mEnableAsciiArmorOutput);
int signatureType;
if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
if (mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
// for sign-only ascii text
signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
} else {
@ -220,12 +199,12 @@ public class PgpSignEncrypt {
ArmoredOutputStream armorOut = null;
OutputStream out;
if (enableAsciiArmorOutput) {
armorOut = new ArmoredOutputStream(outStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(context));
if (mEnableAsciiArmorOutput) {
armorOut = new ArmoredOutputStream(mOutStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
out = armorOut;
} else {
out = outStream;
out = mOutStream;
}
/* Get keys for signature generation for later usage */
@ -233,25 +212,25 @@ public class PgpSignEncrypt {
PGPSecretKeyRing signingKeyRing = null;
PGPPrivateKey signaturePrivateKey = null;
if (enableSignature) {
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId);
signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId);
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, mSignatureKeyId);
signingKey = PgpKeyHelper.getSigningKey(mContext, mSignatureKeyId);
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));
mContext.getString(R.string.error_no_signature_passphrase));
}
updateProgress(R.string.progress_extracting_signature_key, 0, 100);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray());
signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) {
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);
@ -261,23 +240,23 @@ public class PgpSignEncrypt {
if (enableEncryption) {
// has Integrity packet enabled!
JcePGPDataEncryptorBuilder encryptorBuilder =
new JcePGPDataEncryptorBuilder(symmetricEncryptionAlgorithm)
new JcePGPDataEncryptorBuilder(mSymmetricEncryptionAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
.setWithIntegrityPacket(true);
cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
if (encryptionKeyIds.length == 0) {
if (mEncryptionKeyIds.length == 0) {
// Symmetric encryption
Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
new JcePBEKeyEncryptionMethodGenerator(encryptionPassphrase.toCharArray());
new JcePBEKeyEncryptionMethodGenerator(mEncryptionPassphrase.toCharArray());
cPk.addMethod(symmetricEncryptionGenerator);
} else {
// Asymmetric encryption
for (long id : encryptionKeyIds) {
PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(context, id);
for (long id : mEncryptionKeyIds) {
PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(mContext, id);
if (key != null) {
JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
new JcePublicKeyKeyEncryptionMethodGenerator(key);
@ -295,10 +274,10 @@ public class PgpSignEncrypt {
// content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
signingKey.getPublicKey().getAlgorithm(), signatureHashAlgorithm)
signingKey.getPublicKey().getAlgorithm(), mSignatureHashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
if (signatureForceV3) {
if (mSignatureForceV3) {
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
signatureV3Generator.init(signatureType, signaturePrivateKey);
} else {
@ -322,14 +301,14 @@ public class PgpSignEncrypt {
encryptionOut = cPk.open(out, new byte[1 << 16]);
if (enableCompression) {
compressGen = new PGPCompressedDataGenerator(compressionId);
compressGen = new PGPCompressedDataGenerator(mCompressionId);
bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
} else {
bcpgOut = new BCPGOutputStream(encryptionOut);
}
if (enableSignature) {
if (signatureForceV3) {
if (mSignatureForceV3) {
signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
} else {
signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
@ -345,13 +324,13 @@ public class PgpSignEncrypt {
long progress = 0;
int n;
byte[] buffer = new byte[1 << 16];
InputStream in = data.getInputStream();
InputStream in = mData.getInputStream();
while ((n = in.read(buffer)) > 0) {
pOut.write(buffer, 0, n);
// update signature buffer if signature is requested
if (enableSignature) {
if (signatureForceV3) {
if (mSignatureForceV3) {
signatureV3Generator.update(buffer, 0, n);
} else {
signatureGenerator.update(buffer, 0, n);
@ -359,26 +338,26 @@ public class PgpSignEncrypt {
}
progress += n;
if (data.getSize() != 0) {
updateProgress((int) (20 + (95 - 20) * progress / data.getSize()), 100);
if (mData.getSize() != 0) {
updateProgress((int) (20 + (95 - 20) * progress / mData.getSize()), 100);
}
}
literalGen.close();
} else if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
} else if (mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
/* sign-only of ascii text */
updateProgress(R.string.progress_signing, 40, 100);
// write directly on armor output stream
armorOut.beginClearText(signatureHashAlgorithm);
armorOut.beginClearText(mSignatureHashAlgorithm);
InputStream in = data.getInputStream();
InputStream in = mData.getInputStream();
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
final byte[] newline = "\r\n".getBytes("UTF-8");
if (signatureForceV3) {
if (mSignatureForceV3) {
processLine(reader.readLine(), armorOut, signatureV3Generator);
} else {
processLine(reader.readLine(), armorOut, signatureGenerator);
@ -395,7 +374,7 @@ public class PgpSignEncrypt {
armorOut.write(newline);
// update signature buffer with input line
if (signatureForceV3) {
if (mSignatureForceV3) {
signatureV3Generator.update(newline);
processLine(line, armorOut, signatureV3Generator);
} else {
@ -415,7 +394,7 @@ public class PgpSignEncrypt {
if (enableSignature) {
updateProgress(R.string.progress_generating_signature, 95, 100);
if (signatureForceV3) {
if (mSignatureForceV3) {
signatureV3Generator.generate().encode(pOut);
} else {
signatureGenerator.generate().encode(pOut);
@ -432,12 +411,12 @@ public class PgpSignEncrypt {
encryptionOut.close();
}
if (enableAsciiArmorOutput) {
if (mEnableAsciiArmorOutput) {
armorOut.close();
}
out.close();
outStream.close();
mOutStream.close();
updateProgress(R.string.progress_done, 100, 100);
}
@ -449,35 +428,36 @@ public class PgpSignEncrypt {
SignatureException {
OutputStream out;
if (enableAsciiArmorOutput) {
if (mEnableAsciiArmorOutput) {
// Ascii Armor (Radix-64)
ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(context));
ArmoredOutputStream armorOut = new ArmoredOutputStream(mOutStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
out = armorOut;
} else {
out = outStream;
out = mOutStream;
}
if (signatureKeyId == 0) {
throw new PgpGeneralException(context.getString(R.string.error_no_signature_key));
if (mSignatureKeyId == 0) {
throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
}
PGPSecretKeyRing signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId);
PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId);
PGPSecretKeyRing signingKeyRing =
ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, mSignatureKeyId);
PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(mContext, mSignatureKeyId);
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) {
throw new PgpGeneralException(context.getString(R.string.error_no_signature_passphrase));
if (mSignaturePassphrase == null) {
throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_passphrase));
}
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray());
PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) {
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);
@ -490,12 +470,12 @@ public class PgpSignEncrypt {
// content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey
.getPublicKey().getAlgorithm(), signatureHashAlgorithm)
.getPublicKey().getAlgorithm(), mSignatureHashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator signatureGenerator = null;
PGPV3SignatureGenerator signatureV3Generator = null;
if (signatureForceV3) {
if (mSignatureForceV3) {
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
signatureV3Generator.init(type, signaturePrivateKey);
} else {
@ -510,7 +490,7 @@ public class PgpSignEncrypt {
updateProgress(R.string.progress_signing, 40, 100);
InputStream inStream = data.getInputStream();
InputStream inStream = mData.getInputStream();
// if (binary) {
// byte[] buffer = new byte[1 << 16];
// int n = 0;
@ -527,7 +507,7 @@ public class PgpSignEncrypt {
String line;
while ((line = reader.readLine()) != null) {
if (signatureForceV3) {
if (mSignatureForceV3) {
processLine(line, null, signatureV3Generator);
signatureV3Generator.update(newline);
} else {
@ -538,13 +518,13 @@ public class PgpSignEncrypt {
// }
BCPGOutputStream bOut = new BCPGOutputStream(out);
if (signatureForceV3) {
if (mSignatureForceV3) {
signatureV3Generator.generate().encode(bOut);
} else {
signatureGenerator.generate().encode(bOut);
}
out.close();
outStream.close();
mOutStream.close();
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;
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.x509.AuthorityKeyIdentifier;
import org.spongycastle.asn1.x509.BasicConstraints;
import org.spongycastle.asn1.x509.GeneralName;
import org.spongycastle.asn1.x509.GeneralNames;
import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
import org.spongycastle.asn1.x509.X509Extensions;
import org.spongycastle.asn1.x509.X509Name;
import org.spongycastle.asn1.x509.*;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
@ -38,30 +29,38 @@ import org.spongycastle.x509.extension.SubjectKeyIdentifierStructure;
import org.sufficientlysecure.keychain.Constants;
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 final static 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_O = "OpenPGP to X.509 Bridge";
public static final String DN_COMMON_PART_OU = "OpenPGP Keychain cert";
/**
* Creates a self-signed certificate from a public and private key. The (critical) key-usage
* extension is set up with: digital signature, non-repudiation, key-encipherment, key-agreement
* and certificate-signing. The (non-critical) Netscape extension is set up with: SSL client and
* S/MIME. A URI subjectAltName may also be set up.
*
* @param pubKey
* public key
* @param privKey
* private key
* @param subject
* subject (and issuer) DN for this certificate, RFC 2253 format preferred.
* @param startDate
* date from which the certificate will be valid (defaults to current date and time
* if null)
* @param endDate
* date until which the certificate will be valid (defaults to current date and time
* if null) *
* @param subjAltNameURI
* URI to be placed in subjectAltName
*
* @param pubKey public key
* @param privKey private key
* @param subject subject (and issuer) DN for this certificate, RFC 2253 format preferred.
* @param startDate date from which the certificate will be valid (defaults to current date and time
* if null)
* @param endDate date until which the certificate will be valid (defaults to current date and time
* if null) *
* @param subjAltNameURI URI to be placed in subjectAltName
* @return self-signed certificate
* @throws InvalidKeyException
* @throws SignatureException
@ -70,11 +69,10 @@ public class PgpToX509 {
* @throws NoSuchProviderException
* @throws CertificateException
* @throws Exception
*
* @author Bruno Harbulot
*/
public static X509Certificate createSelfSignedCert(PublicKey pubKey, PrivateKey privKey,
X509Name subject, Date startDate, Date endDate, String subjAltNameURI)
X509Name subject, Date startDate, Date endDate, String subjAltNameURI)
throws InvalidKeyException, IllegalStateException, NoSuchAlgorithmException,
SignatureException, CertificateException, NoSuchProviderException {
@ -171,15 +169,12 @@ public class PgpToX509 {
/**
* Creates a self-signed certificate from a PGP Secret Key.
*
* @param pgpSecKey
* PGP Secret Key (from which one can extract the public and private keys and other
* attributes).
* @param pgpPrivKey
* PGP Private Key corresponding to the Secret Key (password callbacks should be done
* before calling this method)
* @param subjAltNameURI
* optional URI to embed in the subject alternative-name
*
* @param pgpSecKey PGP Secret Key (from which one can extract the public and private keys and other
* attributes).
* @param pgpPrivKey PGP Private Key corresponding to the Secret Key (password callbacks should be done
* before calling this method)
* @param subjAltNameURI optional URI to embed in the subject alternative-name
* @return self-signed certificate
* @throws PGPException
* @throws NoSuchProviderException
@ -187,11 +182,10 @@ public class PgpToX509 {
* @throws NoSuchAlgorithmException
* @throws SignatureException
* @throws CertificateException
*
* @author Bruno Harbulot
*/
public static X509Certificate createSelfSignedCert(PGPSecretKey pgpSecKey,
PGPPrivateKey pgpPrivKey, String subjAltNameURI) throws PGPException,
PGPPrivateKey pgpPrivKey, String subjAltNameURI) throws PGPException,
NoSuchProviderException, InvalidKeyException, NoSuchAlgorithmException,
SignatureException, CertificateException {
// get public key from secret key
@ -213,7 +207,7 @@ public class PgpToX509 {
x509NameValues.add(DN_COMMON_PART_OU);
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();
x509NameOids.add(X509Name.CN);
x509NameValues.add("CryptoCall");
@ -225,7 +219,7 @@ public class PgpToX509 {
*/
Log.d(Constants.TAG, "User attributes: ");
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();
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
* configure passwords in advance, but should be used with caution depending on how much you
* allow passwords to be stored within your application.
*
*
* @author Bruno Harbulot.
*
*/
public final static class PredefinedPasswordCallbackHandler implements CallbackHandler {
public static final class PredefinedPasswordCallbackHandler implements CallbackHandler {
private char[] password;
private String prompt;
private char[] mPassword;
private String mPrompt;
public PredefinedPasswordCallbackHandler(String password) {
this(password == null ? null : password.toCharArray(), null);
@ -283,16 +276,16 @@ public class PgpToX509 {
}
public PredefinedPasswordCallbackHandler(char[] password, String prompt) {
this.password = password;
this.prompt = prompt;
this.mPassword = password;
this.mPrompt = prompt;
}
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof PasswordCallback) {
PasswordCallback pwCallback = (PasswordCallback) callback;
if ((this.prompt == null) || (this.prompt.equals(pwCallback.getPrompt()))) {
pwCallback.setPassword(this.password);
if ((this.mPrompt == null) || (this.mPrompt.equals(pwCallback.getPrompt()))) {
pwCallback.setPassword(this.mPassword);
}
} else {
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;
public class NoAsymmetricEncryptionException extends Exception {
@ -6,4 +23,4 @@ public class NoAsymmetricEncryptionException extends Exception {
public NoAsymmetricEncryptionException() {
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;
public class PgpGeneralException extends Exception {
@ -6,4 +23,4 @@ public class PgpGeneralException extends Exception {
public PgpGeneralException(String message) {
super(message);
}
}
}

View File

@ -17,10 +17,9 @@
package org.sufficientlysecure.keychain.provider;
import org.sufficientlysecure.keychain.Constants;
import android.net.Uri;
import android.provider.BaseColumns;
import org.sufficientlysecure.keychain.Constants;
public class KeychainContract {
@ -88,7 +87,6 @@ public class KeychainContract {
public static final String PATH_PUBLIC = "public";
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_KEY_ID = "key_id";
@ -109,14 +107,18 @@ public class KeychainContract {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.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";
/** 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 Uri buildUnifiedKeyRingsUri() {
return CONTENT_URI.buildUpon().appendPath(PATH_UNIFIED).build();
return CONTENT_URI;
}
public static Uri buildPublicKeyRingsUri() {
@ -180,10 +182,14 @@ public class KeychainContract {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.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";
/** 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 Uri buildPublicKeysUri(String keyRingRowId) {
@ -219,10 +225,14 @@ public class KeychainContract {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.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";
/** 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 Uri buildPublicUserIdsUri(String keyRingRowId) {
@ -258,10 +268,14 @@ public class KeychainContract {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.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";
/** 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 Uri buildIdUri(String rowId) {

View File

@ -17,6 +17,10 @@
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.provider.KeychainContract.ApiAppsColumns;
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.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 {
private static final String DATABASE_NAME = "apg.db";
private static final int DATABASE_VERSION = 8;
@ -94,7 +93,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
+ CertsColumns.KEY_ID_CERTIFIER + " INTEGER, " // certifying key
+ CertsColumns.CREATION + " INTEGER, "
+ CertsColumns.VERIFIED + " INTEGER, "
+ CertsColumns.KEY_DATA+ " BLOB)";
+ CertsColumns.KEY_DATA + " BLOB)";
KeychainDatabase(Context context) {

View File

@ -17,22 +17,6 @@
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.ContentValues;
import android.content.UriMatcher;
@ -44,6 +28,13 @@ import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.BaseColumns;
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 static final String ACTION_BROADCAST_DATABASE_CHANGE = Constants.PACKAGE_NAME
@ -104,6 +95,15 @@ public class KeychainProvider extends ContentProvider {
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
*
@ -237,20 +237,11 @@ public class KeychainProvider extends ContentProvider {
+ 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
* <pre>
*
* key_rings/unified
* <pre>
* </pre>
*
*/
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(KeyRingsColumns.KEY_RING_DATA, Tables.KEY_RINGS + "."
+ 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
//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);
// 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;
}
@ -437,9 +433,11 @@ public class KeychainProvider extends ContentProvider {
* Builds default query for keyRings: KeyRings table is joined with UserIds and Keys
*/
private SQLiteQueryBuilder buildKeyRingQuery(SQLiteQueryBuilder qb, int match) {
// public or secret keyring
qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = ");
qb.appendWhereEscapeString(Integer.toString(getKeyType(match)));
if (match != UNIFIED_KEY_RING) {
// public or secret keyring
qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.TYPE + " = ");
qb.appendWhereEscapeString(Integer.toString(getKeyType(match)));
}
// join keyrings with keys and userIds
// 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();
SQLiteDatabase db = mApgDatabase.getReadableDatabase();
String groupBy = null;
int match = mUriMatcher.match(uri);
// screw that switch
if(match == UNIFIED_KEY_RING) {
// 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;
}
// all query() parameters, for good measure
String groupBy = null, having = null;
boolean all = false;
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 SECRET_KEY_RING:
qb = buildKeyRingQuery(qb, match);
@ -740,8 +689,7 @@ public class KeychainProvider extends ContentProvider {
+ Tables.KEYS + "." + Keys.KEY_RING_ROW_ID + " = "
+ "signer." + UserIds.KEY_RING_ROW_ID
+ " AND "
+ Tables.KEYS + "." + Keys.RANK + " = "
+ "signer." + UserIds.RANK
+ "signer." + Keys.RANK + " = 0"
+ ")");
// groupBy = Tables.USER_IDS + "." + UserIds.RANK;
@ -801,7 +749,7 @@ public class KeychainProvider extends ContentProvider {
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
c.setNotificationUri(getContext().getContentResolver(), uri);

View File

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

View File

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

View File

@ -18,11 +18,6 @@
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.ContentUris;
import android.content.ContentValues;
@ -31,7 +26,10 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.Blobs;
import org.sufficientlysecure.keychain.provider.KeychainServiceBlobContract.BlobsColumns;
import org.sufficientlysecure.keychain.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
@ -40,7 +38,7 @@ import java.util.List;
import java.util.UUID;
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;
@ -55,7 +53,9 @@ public class KeychainServiceBlobProvider extends ContentProvider {
return true;
}
/** {@inheritDoc} */
/**
* {@inheritDoc}
*/
@Override
public Uri insert(Uri uri, ContentValues ignored) {
// 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);
}
/** {@inheritDoc} */
/**
* {@inheritDoc}
*/
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws SecurityException,
FileNotFoundException {
@ -91,9 +93,9 @@ public class KeychainServiceBlobProvider extends ContentProvider {
// get the data
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 + " = ?",
new String[] { id, key }, null, null, null);
new String[]{id, key}, null, null, null);
if (result.getCount() == 0) {
// either the key is wrong or no id exists
@ -124,26 +126,34 @@ public class KeychainServiceBlobProvider extends ContentProvider {
return null;
}
/** {@inheritDoc} */
/**
* {@inheritDoc}
*/
@Override
public String getType(Uri uri) {
return null;
}
/** {@inheritDoc} */
/**
* {@inheritDoc}
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
String sortOrder) {
return null;
}
/** {@inheritDoc} */
/**
* {@inheritDoc}
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
/** {@inheritDoc} */
/**
* {@inheritDoc}
*/
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;

View File

@ -17,24 +17,17 @@
package org.sufficientlysecure.keychain.provider;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
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.UserAttributePacket;
import org.spongycastle.bcpg.UserAttributeSubpacket;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import android.content.*;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
import android.os.RemoteException;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.openpgp.*;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.sufficientlysecure.keychain.Constants;
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.Log;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
import android.os.RemoteException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class ProviderHelper {
@ -124,7 +115,7 @@ public class ProviderHelper {
public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long 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
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()) {
currentRowId = oldQuery.getLong(0);
} else {
@ -191,10 +183,12 @@ public class ProviderHelper {
ContentValues values = new ContentValues();
// use exactly the same _ID again to replace key in-place.
// NOTE: If we would not use the same _ID again, getting back to the ViewKeyActivity would result in Nullpointer,
// 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
if (currentRowId != -1)
if (currentRowId != -1) {
values.put(KeyRings._ID, currentRowId);
}
values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
@ -279,7 +273,8 @@ public class ProviderHelper {
// get current _ID of key
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()) {
currentRowId = oldQuery.getLong(0);
} else {
@ -295,10 +290,12 @@ public class ProviderHelper {
ContentValues values = new ContentValues();
// use exactly the same _ID again to replace key in-place.
// NOTE: If we would not use the same _ID again, getting back to the ViewKeyActivity would result in Nullpointer,
// 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
if (currentRowId != -1)
if (currentRowId != -1) {
values.put(KeyRings._ID, currentRowId);
}
values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
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
*/
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();
values.put(Keys.KEY_ID, key.getKeyID());
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
*/
private static ContentProviderOperation buildPublicUserIdOperations(Context context,
long keyRingRowId, String userId, int rank) {
long keyRingRowId, String userId, int rank) {
ContentValues values = new ContentValues();
values.put(UserIds.KEY_RING_ROW_ID, keyRingRowId);
values.put(UserIds.USER_ID, userId);
@ -402,7 +399,7 @@ public class ProviderHelper {
* Build ContentProviderOperation to add PGPSecretKey to database corresponding to a keyRing
*/
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();
boolean hasPrivate = true;
@ -439,7 +436,7 @@ public class ProviderHelper {
* Build ContentProviderOperation to add SecretUserIds to database corresponding to a keyRing
*/
private static ContentProviderOperation buildSecretUserIdOperations(Context context,
long keyRingRowId, String userId, int rank) {
long keyRingRowId, String userId, int rank) {
ContentValues values = new ContentValues();
values.put(UserIds.KEY_RING_ROW_ID, keyRingRowId);
values.put(UserIds.USER_ID, userId);
@ -483,10 +480,10 @@ public class ProviderHelper {
ArrayList<Long> rowIds = new ArrayList<Long>();
if (cursor != null) {
int IdCol = cursor.getColumnIndex(KeyRings._ID);
int idCol = cursor.getColumnIndex(KeyRings._ID);
if (cursor.moveToFirst()) {
do {
rowIds.add(cursor.getLong(IdCol));
rowIds.add(cursor.getLong(idCol));
} while (cursor.moveToNext());
}
}
@ -566,7 +563,7 @@ public class ProviderHelper {
+ " AS sign_keys WHERE sign_keys." + Keys.KEY_RING_ROW_ID + " = "
+ KeychainDatabase.Tables.KEY_RINGS + "." + KeyRings._ID
+ " AND sign_keys." + Keys.CAN_SIGN + " = '1' AND " + Keys.IS_MASTER_KEY
+ " = 1) AS sign",};
+ " = 1) AS sign", };
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(queryUri, projection, null, null, null);

View File

@ -17,48 +17,6 @@
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.content.Context;
import android.content.Intent;
@ -67,13 +25,32 @@ import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
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
* data from the activities or other apps, queues these intents, executes them, and stops itself
* after doing them.
*/
public class KeychainIntentService extends IntentService implements ProgressDialogUpdater {
public class KeychainIntentService extends IntentService
implements ProgressDialogUpdater, KeychainServiceListener {
/* extras that can be given by intent */
public static final String EXTRA_MESSENGER = "messenger";
@ -331,8 +308,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
builder.enableAsciiArmorOutput(useAsciiArmor)
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.signatureKeyId(secretKeyId)
.signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
.signatureHashAlgorithm(
Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(
PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().generateSignature();
} else if (signOnly) {
@ -340,21 +319,26 @@ public class KeychainIntentService extends IntentService implements ProgressDial
builder.enableAsciiArmorOutput(useAsciiArmor)
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.signatureKeyId(secretKeyId)
.signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
.signatureHashAlgorithm(
Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(
PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().execute();
} else {
Log.d(Constants.TAG, "encrypt...");
builder.enableAsciiArmorOutput(useAsciiArmor)
.compressionId(compressionId)
.symmetricEncryptionAlgorithm(Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
.symmetricEncryptionAlgorithm(
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.encryptionKeyIds(encryptionKeyIds)
.encryptionPassphrase(encryptionPassphrase)
.signatureKeyId(secretKeyId)
.signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
.signatureHashAlgorithm(
Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(
PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().execute();
}
@ -546,7 +530,8 @@ public class KeychainIntentService extends IntentService implements ProgressDial
ArrayList<PGPSecretKey> keys = PgpConversionHelper.BytesToPGPSecretKeyList(data
.getByteArray(SAVE_KEYRING_KEYS));
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);
@ -601,7 +586,8 @@ public class KeychainIntentService extends IntentService implements ProgressDial
int keysTotal = 2;
int keysCreated = 0;
setProgress(
getApplicationContext().getResources().getQuantityString(R.plurals.progress_generating, keysTotal),
getApplicationContext().getResources().
getQuantityString(R.plurals.progress_generating, keysTotal),
keysCreated,
keysTotal);
PgpKeyOperation keyOperations = new PgpKeyOperation(this, this);
@ -705,17 +691,22 @@ public class KeychainIntentService extends IntentService implements ProgressDial
keyRingRowIds = ProviderHelper.getSecretKeyRingsRowIds(this);
}
} else {
for(long rowId : rowIds) {
for (long rowId : rowIds) {
keyRingRowIds.add(rowId);
}
}
Bundle resultData;
PgpImportExport pgpImportExport = new PgpImportExport(this, this);
PgpImportExport pgpImportExport = new PgpImportExport(this, this, this);
resultData = pgpImportExport
.exportKeyRings(keyRingRowIds, keyType, outStream);
if (mIsCanceled) {
boolean isDeleted = new File(outputFile).delete();
}
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
} catch (Exception 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
// PGPObject chunks after the first one, e.g. files with several consecutive ASCII
// armor blocks
BufferedInputStream bufferedInput = new BufferedInputStream(new ByteArrayInputStream(downloadedKey));
BufferedInputStream bufferedInput =
new BufferedInputStream(new ByteArrayInputStream(downloadedKey));
try {
// 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) {
// Service was canceled. Do not send error to handler.
if (this.mIsCanceled)
if (this.mIsCanceled) {
return;
}
Log.e(Constants.TAG, "ApgService Exception: ", e);
e.printStackTrace();
@ -850,9 +842,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
private void sendMessageToHandler(Integer arg1, Integer arg2, Bundle data) {
// Service was canceled. Do not send message to handler.
if (this.mIsCanceled)
if (this.mIsCanceled) {
return;
}
Message msg = Message.obtain();
msg.arg1 = arg1;
if (arg2 != null) {
@ -903,4 +895,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public void setProgress(int progress, int max) {
setProgress(null, progress, max);
}
@Override
public boolean hasServiceStopped() {
return mIsCanceled;
}
}

View File

@ -17,9 +17,6 @@
package org.sufficientlysecure.keychain.service;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.R;
import android.app.Activity;
import android.content.DialogInterface.OnCancelListener;
import android.os.Bundle;
@ -28,6 +25,8 @@ import android.os.Message;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.widget.Toast;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
public class KeychainIntentServiceHandler extends Handler {
@ -73,7 +72,8 @@ public class KeychainIntentServiceHandler extends Handler {
}
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();
Handler handler = new Handler();
handler.post(new Runnable() {

View File

@ -17,10 +17,15 @@
package org.sufficientlysecure.keychain.service;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.*;
import android.util.Log;
import android.util.LongSparseArray;
import org.spongycastle.openpgp.PGPException;
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.provider.ProviderHelper;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import java.util.Date;
import java.util.Iterator;
/**
* This service runs in its own process, but is available to all other processes as the main
* passphrase cache. Use the static methods addCachedPassphrase and getCachedPassphrase for
* convenience.
*
*/
public class PassphraseCacheService extends Service {
public static final String TAG = Constants.TAG + ": PassphraseCacheService";
@ -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
* service is only run once. Thus, when the service is already started, new commands just add
* new events to the alarm manager for new passphrases to let them timeout in the future.
*
*
* @param context
* @param keyId
* @param passphrase
@ -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
* designed to wait until the service returns the passphrase.
*
*
* @param context
* @param keyId
* @return passphrase or null (if no passphrase is cached for this keyId)
@ -161,7 +151,7 @@ public class PassphraseCacheService extends Service {
/**
* Internal implementation to get cached passphrase.
*
*
* @param keyId
* @return
*/
@ -205,7 +195,7 @@ public class PassphraseCacheService extends Service {
/**
* Checks if key has a passphrase.
*
*
* @param secretKeyId
* @return true if it has a passphrase
*/
@ -216,17 +206,17 @@ public class PassphraseCacheService extends Service {
.getPGPSecretKeyRingByKeyId(context, secretKeyId);
PGPSecretKey secretKey = null;
boolean foundValidKey = false;
for (Iterator keys = secRing.getSecretKeys(); keys.hasNext();) {
secretKey = (PGPSecretKey)keys.next();
for (Iterator keys = secRing.getSecretKeys(); keys.hasNext(); ) {
secretKey = (PGPSecretKey) keys.next();
if (!secretKey.isPrivateKeyEmpty()) {
foundValidKey = true;
break;
}
}
if (!foundValidKey)
if (!foundValidKey) {
return false;
}
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
"SC").build("".toCharArray());
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
*
*
* @param context
* @param keyId
* @return
@ -337,7 +327,7 @@ public class PassphraseCacheService extends Service {
/**
* Called when one specific passphrase for keyId timed out
*
*
* @param context
* @param keyId
*/

View File

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

View File

@ -17,12 +17,6 @@
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.net.Uri;
import android.os.Bundle;
@ -30,6 +24,11 @@ import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log;
public class AppSettingsActivity extends ActionBarActivity {
private Uri mAppUri;
@ -41,7 +40,8 @@ public class AppSettingsActivity extends ActionBarActivity {
super.onCreate(savedInstanceState);
// 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() {
@Override
public void onClick(View v) {
@ -77,12 +77,12 @@ public class AppSettingsActivity extends ActionBarActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_api_settings_revoke:
revokeAccess();
return true;
case R.id.menu_api_settings_cancel:
finish();
return true;
case R.id.menu_api_settings_revoke:
revokeAccess();
return true;
case R.id.menu_api_settings_cancel:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}

View File

@ -17,17 +17,6 @@
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.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@ -40,20 +29,25 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.AdapterView;
import android.widget.*;
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 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
SelectSecretKeyLayoutFragment.SelectSecretKeyCallback {
// model
private AppSettings appSettings;
private AppSettings mAppSettings;
// view
private LinearLayout mAdvancedSettingsContainer;
@ -68,16 +62,16 @@ public class AppSettingsFragment extends Fragment implements
private SelectSecretKeyLayoutFragment mSelectKeyFragment;
KeyValueSpinnerAdapter encryptionAdapter;
KeyValueSpinnerAdapter hashAdapter;
KeyValueSpinnerAdapter compressionAdapter;
KeyValueSpinnerAdapter mEncryptionAdapter;
KeyValueSpinnerAdapter mHashAdapter;
KeyValueSpinnerAdapter mCompressionAdapter;
public AppSettings getAppSettings() {
return appSettings;
return mAppSettings;
}
public void setAppSettings(AppSettings appSettings) {
this.appSettings = appSettings;
this.mAppSettings = appSettings;
setPackage(appSettings.getPackageName());
mPackageName.setText(appSettings.getPackageName());
@ -93,10 +87,10 @@ public class AppSettingsFragment extends Fragment implements
}
mSelectKeyFragment.selectKey(appSettings.getKeyId());
mEncryptionAlgorithm.setSelection(encryptionAdapter.getPosition(appSettings
mEncryptionAlgorithm.setSelection(mEncryptionAdapter.getPosition(appSettings
.getEncryptionAlgorithm()));
mHashAlgorithm.setSelection(hashAdapter.getPosition(appSettings.getHashAlgorithm()));
mCompression.setSelection(compressionAdapter.getPosition(appSettings.getCompression()));
mHashAlgorithm.setSelection(mHashAdapter.getPosition(appSettings.getHashAlgorithm()));
mCompression.setSelection(mCompressionAdapter.getPosition(appSettings.getCompression()));
}
/**
@ -139,14 +133,14 @@ public class AppSettingsFragment extends Fragment implements
AlgorithmNames algorithmNames = new AlgorithmNames(getActivity());
encryptionAdapter = new KeyValueSpinnerAdapter(getActivity(),
mEncryptionAdapter = new KeyValueSpinnerAdapter(getActivity(),
algorithmNames.getEncryptionNames());
mEncryptionAlgorithm.setAdapter(encryptionAdapter);
mEncryptionAlgorithm.setAdapter(mEncryptionAdapter);
mEncryptionAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
appSettings.setEncryptionAlgorithm((int) id);
mAppSettings.setEncryptionAlgorithm((int) id);
}
@Override
@ -154,13 +148,13 @@ public class AppSettingsFragment extends Fragment implements
}
});
hashAdapter = new KeyValueSpinnerAdapter(getActivity(), algorithmNames.getHashNames());
mHashAlgorithm.setAdapter(hashAdapter);
mHashAdapter = new KeyValueSpinnerAdapter(getActivity(), algorithmNames.getHashNames());
mHashAlgorithm.setAdapter(mHashAdapter);
mHashAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
appSettings.setHashAlgorithm((int) id);
mAppSettings.setHashAlgorithm((int) id);
}
@Override
@ -168,14 +162,14 @@ public class AppSettingsFragment extends Fragment implements
}
});
compressionAdapter = new KeyValueSpinnerAdapter(getActivity(),
mCompressionAdapter = new KeyValueSpinnerAdapter(getActivity(),
algorithmNames.getCompressionNames());
mCompression.setAdapter(compressionAdapter);
mCompression.setAdapter(mCompressionAdapter);
mCompression.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
appSettings.setCompression((int) id);
mAppSettings.setCompression((int) id);
}
@Override
@ -237,7 +231,7 @@ public class AppSettingsFragment extends Fragment implements
*/
@Override
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.os.IBinder;
import android.os.ParcelFileDescriptor;
import org.openintents.openpgp.IOpenPgpService;
import org.openintents.openpgp.OpenPgpError;
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_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
Intent result = new Intent();
@ -126,7 +126,8 @@ public class OpenPgpService extends RemoteService {
intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId);
// pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0);
PendingIntent pi = PendingIntent.getActivity
(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0);
// return PendingIntent to be executed by client
Intent result = new Intent();
@ -208,7 +209,8 @@ public class OpenPgpService extends RemoteService {
} else {
Intent result = new Intent();
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);
return result;
}
@ -289,7 +291,8 @@ public class OpenPgpService extends RemoteService {
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
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);
// 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!
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) {
Intent result = new Intent();
OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!");
OpenPgpError error = new OpenPgpError
(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!");
result.putExtra(OpenPgpApi.RESULT_ERROR, error);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;

View File

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

View File

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

View File

@ -17,10 +17,6 @@
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.Intent;
import android.database.Cursor;
@ -33,6 +29,9 @@ import android.support.v4.content.Loader;
import android.view.View;
import android.widget.AdapterView;
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
LoaderManager.LoaderCallbacks<Cursor> {
@ -71,7 +70,7 @@ public class RegisteredAppsListFragment extends ListFragment implements
}
// 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) {
// 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);
}
}
}

View File

@ -17,17 +17,6 @@
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.Service;
import android.content.Context;
@ -38,6 +27,16 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.net.Uri;
import android.os.Binder;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
/**
* 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_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
Intent result = new Intent();
@ -98,10 +98,12 @@ public abstract class RemoteService extends Service {
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE);
intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, getString(R.string.api_error_wrong_signature));
intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE,
getString(R.string.api_error_wrong_signature));
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
Intent result = new Intent();
@ -138,8 +140,9 @@ public abstract class RemoteService extends Service {
AppSettings settings = ProviderHelper.getApiAppSettings(this, uri);
if (settings != null)
if (settings != null) {
return settings;
}
}
return null;
@ -213,7 +216,7 @@ public abstract class RemoteService extends Service {
return true;
} else {
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.support.v7.app.ActionBarActivity;
import android.view.View;
import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.htmltextview.HtmlTextView;
import org.sufficientlysecure.keychain.Constants;
@ -88,7 +87,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE);
// 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() {
@Override
public void onClick(View v) {
@ -108,13 +108,14 @@ public class RemoteServiceActivity extends ActionBarActivity {
RemoteServiceActivity.this.finish();
}
}
}, R.string.api_register_disallow, R.drawable.ic_action_cancel, new View.OnClickListener() {
@Override
public void onClick(View v) {
// Disallow
RemoteServiceActivity.this.setResult(RESULT_CANCELED);
RemoteServiceActivity.this.finish();
}
}, R.string.api_register_disallow, R.drawable.ic_action_cancel,
new View.OnClickListener() {
@Override
public void onClick(View v) {
// Disallow
RemoteServiceActivity.this.setResult(RESULT_CANCELED);
RemoteServiceActivity.this.finish();
}
}
);
@ -161,7 +162,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
}
// 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() {
@Override
public void onClick(View v) {
@ -214,7 +216,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
String text = "<font color=\"red\">" + errorMessage + "</font>";
// Inflate a "Done" custom action bar view
ActionBarHelper.setOneButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done,
ActionBarHelper.setOneButtonView(getSupportActionBar(),
R.string.btn_okay, R.drawable.ic_action_done,
new View.OnClickListener() {
@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;
public class WrongPackageSignatureException extends Exception {
@ -7,4 +24,4 @@ public class WrongPackageSignatureException extends Exception {
public WrongPackageSignatureException(String message) {
super(message);
}
}
}

View File

@ -17,8 +17,20 @@
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.PGPSignature;
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.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.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;
import java.util.Iterator;
/**
* 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);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, Preferences.getPreferences(this)
.getKeyServers());
.getKeyServers());
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSelectKeyserverSpinner.setAdapter(adapter);

View File

@ -17,37 +17,6 @@
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.app.ProgressDialog;
import android.content.Intent;
@ -59,16 +28,34 @@ import android.os.Messenger;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AnimationUtils;
import android.widget.CheckBox;
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 android.widget.*;
import com.beardedhen.androidbootstrap.BootstrapButton;
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")
public class DecryptActivity extends DrawerActivity {
@ -364,7 +351,7 @@ public class DecryptActivity extends DrawerActivity {
}
} else {
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)
.show();
// end activity
@ -383,7 +370,7 @@ public class DecryptActivity extends DrawerActivity {
if (filename.endsWith(".asc") || filename.endsWith(".gpg") || filename.endsWith(".pgp")) {
filename = filename.substring(0, filename.length() - 4);
}
mOutputFilename = Constants.path.APP_DIR + "/" + filename;
mOutputFilename = Constants.Path.APP_DIR + "/" + filename;
}
private void updateSource() {
@ -532,8 +519,11 @@ public class DecryptActivity extends DrawerActivity {
AppMsg.STYLE_ALERT).show();
} finally {
try {
if (inStream != null) inStream.close();
} catch (Exception e){ }
if (inStream != null) {
inStream.close();
}
} catch (Exception e) {
}
}
} else {
inStream = new ByteArrayInputStream(mMessage.getText().toString().getBytes());

View File

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

View File

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

View File

@ -17,9 +17,22 @@
package org.sufficientlysecure.keychain.ui;
import java.io.File;
import java.util.Vector;
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.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.PGPPublicKeyRing;
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.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.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;
import java.io.File;
import java.util.Vector;
public class EncryptActivity extends DrawerActivity {
@ -858,7 +848,7 @@ public class EncryptActivity extends DrawerActivity {
new Choice(Id.choice.compression.zlib, "ZLIB ("
+ getString(R.string.compression_fast) + ")"),
new Choice(Id.choice.compression.bzip2, "BZIP2 ("
+ getString(R.string.compression_very_slow) + ")"),};
+ getString(R.string.compression_very_slow) + ")"), };
ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(this,
android.R.layout.simple_spinner_item, choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

View File

@ -17,11 +17,6 @@
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.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@ -31,6 +26,10 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.sufficientlysecure.htmltextview.HtmlTextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
public class HelpAboutFragment extends Fragment {
@ -55,7 +54,7 @@ public class HelpAboutFragment extends Fragment {
/**
* Get the current package version.
*
*
* @return The current version.
*/
private String getVersion() {
@ -73,4 +72,4 @@ public class HelpAboutFragment extends Fragment {
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
* it under the terms of the GNU General Public License as published by
@ -17,19 +17,16 @@
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.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
public class HelpActivity extends ActionBarActivity {
public static final String EXTRA_SELECTED_TAB = "selectedTab";
public static final String EXTRA_SELECTED_TAB = "selected_tab";
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
@ -59,19 +56,24 @@ public class HelpActivity extends ActionBarActivity {
Bundle startBundle = new Bundle();
startBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_start);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_start)),
HelpHtmlFragment.class, startBundle, (selectedTab == 0) );
HelpHtmlFragment.class, startBundle, (selectedTab == 0));
Bundle faqBundle = new Bundle();
faqBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_faq);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_faq)),
HelpHtmlFragment.class, faqBundle, (selectedTab == 1));
Bundle nfcBundle = new Bundle();
nfcBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_nfc_beam);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_nfc_beam)),
HelpHtmlFragment.class, nfcBundle, (selectedTab == 1) );
HelpHtmlFragment.class, nfcBundle, (selectedTab == 2));
Bundle changelogBundle = new Bundle();
changelogBundle.putInt(HelpHtmlFragment.ARG_HTML_FILE, R.raw.help_changelog);
mTabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.help_tab_changelog)),
HelpHtmlFragment.class, changelogBundle, (selectedTab == 2) );
HelpHtmlFragment.class, changelogBundle, (selectedTab == 3));
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;
import org.sufficientlysecure.htmltextview.HtmlTextView;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@ -27,11 +25,12 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;
import org.sufficientlysecure.htmltextview.HtmlTextView;
public class HelpHtmlFragment extends Fragment {
private Activity mActivity;
private int htmlFile;
private int mHtmlFile;
public static final String ARG_HTML_FILE = "htmlFile";
@ -52,8 +51,8 @@ public class HelpHtmlFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mActivity = getActivity();
htmlFile = getArguments().getInt(ARG_HTML_FILE);
mHtmlFile = getArguments().getInt(ARG_HTML_FILE);
ScrollView scroller = new ScrollView(mActivity);
HtmlTextView text = new HtmlTextView(mActivity);
@ -66,11 +65,11 @@ public class HelpHtmlFragment extends Fragment {
scroller.addView(text);
// 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
text.setTextColor(getResources().getColor(android.R.color.black));
return scroller;
}
}
}

View File

@ -34,10 +34,8 @@ import android.support.v7.app.ActionBar;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import com.beardedhen.androidbootstrap.BootstrapButton;
import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
@ -169,7 +167,8 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
query = "0x" + fingerprint;
}
} 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;
}
@ -338,7 +337,7 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
// } else {
// status.putString(
// 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) {
@ -400,7 +399,8 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO)
.show();
if (bad > 0) {
BadImportKeyDialogFragment badImportKeyDialogFragment = BadImportKeyDialogFragment.newInstance(bad);
BadImportKeyDialogFragment badImportKeyDialogFragment =
BadImportKeyDialogFragment.newInstance(bad);
badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog");
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -17,14 +17,6 @@
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.net.Uri;
import android.os.Bundle;
@ -36,9 +28,15 @@ import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton;
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 {
@ -94,45 +92,45 @@ public class ImportKeysQrCodeFragment extends Fragment {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode & 0xFFFF) {
case IntentIntegratorSupportV4.REQUEST_CODE: {
IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode,
resultCode, data);
if (scanResult != null && scanResult.getFormatName() != null) {
String scannedContent = scanResult.getContents();
case IntentIntegratorSupportV4.REQUEST_CODE: {
IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode,
resultCode, data);
if (scanResult != null && scanResult.getFormatName() != null) {
String scannedContent = scanResult.getContents();
Log.d(Constants.TAG, "scannedContent: " + scannedContent);
Log.d(Constants.TAG, "scannedContent: " + scannedContent);
// look if it's fingerprint only
if (scannedContent.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) {
importFingerprint(Uri.parse(scanResult.getContents()));
return;
// look if it's fingerprint only
if (scannedContent.toLowerCase(Locale.ENGLISH).startsWith(Constants.FINGERPRINT_SCHEME)) {
importFingerprint(Uri.parse(scanResult.getContents()));
return;
}
// look if it is the whole key
String[] parts = scannedContent.split(",");
if (parts.length == 3) {
importParts(parts);
return;
}
// is this a full key encoded as qr code?
if (scannedContent.startsWith("-----BEGIN PGP")) {
mImportActivity.loadCallback(scannedContent.getBytes(), null, null, null);
return;
}
// fail...
Toast.makeText(getActivity(), R.string.import_qr_code_wrong, Toast.LENGTH_LONG)
.show();
}
// look if it is the whole key
String[] parts = scannedContent.split(",");
if (parts.length == 3) {
importParts(parts);
return;
}
// is this a full key encoded as qr code?
if (scannedContent.startsWith("-----BEGIN PGP")) {
mImportActivity.loadCallback(scannedContent.getBytes(), null, null, null);
return;
}
// fail...
Toast.makeText(getActivity(), R.string.import_qr_code_wrong, Toast.LENGTH_LONG)
.show();
break;
}
break;
}
default:
super.onActivityResult(requestCode, resultCode, data);
default:
super.onActivityResult(requestCode, resultCode, data);
break;
break;
}
}

View File

@ -17,11 +17,6 @@
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.os.Bundle;
import android.support.v4.app.Fragment;
@ -36,8 +31,11 @@ import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.util.Log;
public class ImportKeysServerFragment extends Fragment {
public static final String ARG_QUERY = "query";
@ -96,7 +94,8 @@ public class ImportKeysServerFragment extends Fragment {
search(query, keyServer);
// 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);
}
});
@ -110,7 +109,6 @@ public class ImportKeysServerFragment extends Fragment {
search(query, keyServer);
// 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;

View File

@ -17,15 +17,14 @@
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.os.Bundle;
import android.view.Menu;
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 {
@ -53,19 +52,45 @@ public class KeyListActivity extends DrawerActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_key_list_import:
Intent intentImport = new Intent(this, ImportKeysActivity.class);
startActivityForResult(intentImport, 0);
case R.id.menu_key_list_import:
Intent intentImport = new Intent(this, ImportKeysActivity.class);
startActivityForResult(intentImport, 0);
return true;
case R.id.menu_key_list_export:
// TODO fix this for unified keylist
mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.path.APP_DIR_FILE_PUB);
return true;
case R.id.menu_key_list_export:
// TODO fix this for unified keylist
mExportHelper.showExportKeysDialog(null, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB);
return true;
default:
return super.onOptionsItemSelected(item);
return true;
case R.id.menu_key_list_create:
createKey();
return true;
case R.id.menu_key_list_create_expert:
createKeyExpert();
return true;
case R.id.menu_key_list_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
* it under the terms of the GNU General Public License as published by
@ -17,28 +17,6 @@
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.TargetApi;
import android.content.Context;
@ -46,45 +24,47 @@ import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.*;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
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.*;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.*;
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 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
* 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> {
private KeyListAdapter mAdapter;
@ -202,6 +182,23 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
showDeleteKeyDialog(mode, ids);
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;
}
@ -254,8 +251,15 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
};
static final int INDEX_TYPE = 1;
static final int INDEX_UID = 3;
static final String SORT_ORDER = UserIds.USER_ID + " ASC";
static final int INDEX_MASTER_KEY_ID = 2;
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
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
@ -310,9 +314,10 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
} else {
viewIntent = new Intent(getActivity(), ViewKeyActivityJB.class);
}
viewIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsByMasterKeyIdUri(
Long.toString(mAdapter.getMasterKeyId(position)))
);
viewIntent.setData(
KeychainContract
.KeyRings.buildPublicKeyRingsByMasterKeyIdUri(
Long.toString(mAdapter.getMasterKeyId(position))));
startActivity(viewIntent);
}
@ -349,8 +354,12 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
for (String userId : notDeleted) {
notDeletedMsg += userId + "\n";
}
Toast.makeText(getActivity(), getString(R.string.error_can_not_delete_contacts, notDeletedMsg)
+ getResources().getQuantityString(R.plurals.error_can_not_delete_info, notDeleted.size()),
Toast.makeText(getActivity(),
getString(R.string.error_can_not_delete_contacts, notDeletedMsg)
+ getResources()
.getQuantityString(
R.plurals.error_can_not_delete_info,
notDeleted.size()),
Toast.LENGTH_LONG).show();
mode.finish();
@ -452,45 +461,22 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
/**
* Implements StickyListHeadersAdapter from library
*/
private class KeyListAdapter extends CursorAdapter implements StickyListHeadersAdapter {
private class KeyListAdapter extends HighlightQueryCursorAdapter implements StickyListHeadersAdapter {
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>();
public KeyListAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
mInflater = LayoutInflater.from(context);
initIndex(c);
}
@Override
public Cursor swapCursor(Cursor newCursor) {
initIndex(newCursor);
return super.swapCursor(newCursor);
}
/**
* Get column indexes for performance reasons just once in constructor and swapCursor. For a
* performance comparison see http://stackoverflow.com/a/17999582
*
* @param cursor
*/
private void initIndex(Cursor cursor) {
if (cursor != null) {
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
* <p/>
@ -504,15 +490,15 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
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);
if (userIdSplit[0] != null) {
mainUserId.setText(highlightSearchQuery(userIdSplit[0]));
mainUserId.setText(highlightSearchQuery(userIdSplit[0]));
} else {
mainUserId.setText(R.string.user_id_no_name);
}
if (userIdSplit[1] != null) {
mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1]));
mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1]));
mainUserIdRest.setVisibility(View.VISIBLE);
} else {
mainUserIdRest.setVisibility(View.GONE);
@ -523,12 +509,12 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
Button button = (Button) view.findViewById(R.id.edit);
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
revoked.setVisibility(View.GONE);
button.setVisibility(View.VISIBLE);
final long id = cursor.getLong(mMasterKeyId);
final long id = cursor.getLong(INDEX_MASTER_KEY_ID);
button.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
@ -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
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);
}
}
@ -553,23 +539,11 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
}
public long getMasterKeyId(int id) {
if (!mCursor.moveToPosition(id)) {
throw new IllegalStateException("couldn't move cursor to position " + id);
}
return mCursor.getLong(mMasterKeyId);
}
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);
return mCursor.getLong(INDEX_MASTER_KEY_ID);
}
@Override
@ -590,8 +564,8 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
if (convertView == null) {
holder = new HeaderViewHolder();
convertView = mInflater.inflate(R.layout.key_list_header, parent, false);
holder.text = (TextView) convertView.findViewById(R.id.stickylist_header_text);
holder.count = (TextView) convertView.findViewById(R.id.contacts_num);
holder.mText = (TextView) convertView.findViewById(R.id.stickylist_header_text);
holder.mCount = (TextView) convertView.findViewById(R.id.contacts_num);
convertView.setTag(holder);
} else {
holder = (HeaderViewHolder) convertView.getTag();
@ -607,26 +581,26 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
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
int num = mCursor.getCount();
String contactsTotal = getResources().getQuantityString(R.plurals.n_contacts, num, num);
holder.count.setText(contactsTotal);
holder.count.setVisibility(View.VISIBLE);
holder.mCount.setText(contactsTotal);
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;
}
// 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);
if (userId != null && userId.length() > 0) {
headerText = "" + userId.subSequence(0, 1).charAt(0);
}
holder.text.setText(headerText);
holder.count.setVisibility(View.GONE);
holder.mText.setText(headerText);
holder.mCount.setVisibility(View.GONE);
return convertView;
}
@ -646,11 +620,11 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
}
// 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;
}
// 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) {
return userId.charAt(0);
} else {
@ -659,8 +633,8 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
}
class HeaderViewHolder {
TextView text;
TextView count;
TextView mText;
TextView mCount;
}
/**
@ -675,8 +649,9 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
long[] ids = new long[mSelection.size()];
int i = 0;
// get master key ids
for (int pos : mSelection.keySet())
for (int pos : mSelection.keySet()) {
ids[i++] = mAdapter.getMasterKeyId(pos);
}
return ids;
}
@ -698,43 +673,17 @@ public class KeyListFragment extends Fragment implements SearchView.OnQueryTextL
/**
* Change color for multi-selection
*/
// default color
v.setBackgroundColor(Color.TRANSPARENT);
if (mSelection.get(position) != null) {
// this is a selected position, change color!
// selected position color
v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
} else {
// default color
v.setBackgroundColor(Color.TRANSPARENT);
}
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;
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.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Constants;
@ -24,24 +29,13 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences;
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;
@SuppressLint("NewApi")
public class PreferencesActivity extends PreferenceActivity {
public final static 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_GEN = "org.sufficientlysecure.keychain.ui.PREFS_GEN";
public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV";
private PreferenceScreen mKeyServerPreference = null;
private static Preferences mPreferences;
@ -62,9 +56,9 @@ public class PreferencesActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.gen_preferences);
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();
mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers,
servers.length, servers.length));
@ -84,11 +78,11 @@ public class PreferencesActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.adv_preferences);
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, };
String[] entries = new String[] {
String[] entries = new String[]{
getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")",
"ZIP (" + getString(R.string.compression_fast) + ")",
"ZLIB (" + getString(R.string.compression_fast) + ")",
@ -99,20 +93,22 @@ public class PreferencesActivity extends PreferenceActivity {
}
initializeHashAlgorithm(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM),
valueIds, entries, values);
(IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM),
valueIds, entries, values);
initializeMessageCompression(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION),
valueIds, entries, values);
(IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION),
valueIds, entries, values);
initializeFileCompression(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION),
entries, values);
(IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION),
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) {
// Load the legacy preferences headers
@ -149,7 +145,9 @@ public class PreferencesActivity extends PreferenceActivity {
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 {
private PreferenceScreen mKeyServerPreference = null;
@ -162,9 +160,9 @@ public class PreferencesActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.gen_preferences);
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();
mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers,
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 {
@Override
@ -215,11 +215,11 @@ public class PreferencesActivity extends PreferenceActivity {
addPreferencesFromResource(R.xml.adv_preferences);
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, };
String[] entries = new String[] {
String[] entries = new String[]{
getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")",
"ZIP (" + getString(R.string.compression_fast) + ")",
"ZLIB (" + getString(R.string.compression_fast) + ")",
@ -230,24 +230,26 @@ public class PreferencesActivity extends PreferenceActivity {
}
initializeHashAlgorithm(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM),
valueIds, entries, values);
(IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM),
valueIds, entries, values);
initializeMessageCompression(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION),
valueIds, entries, values);
(IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION),
valueIds, entries, values);
initializeFileCompression(
(IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION),
(IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION),
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)
|| GeneralPrefsFragment.class.getName().equals(fragmentName)
|| super.isValidFragment(fragmentName);
@ -268,11 +270,11 @@ public class PreferencesActivity extends PreferenceActivity {
}
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.CAST5, PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES,
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", };
String values[] = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
@ -296,10 +298,10 @@ public class PreferencesActivity extends PreferenceActivity {
private static void initializeHashAlgorithm
(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.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", };
values = new String[valueIds.length];
for (int i = 0; i < values.length; ++i) {
@ -319,8 +321,9 @@ public class PreferencesActivity extends PreferenceActivity {
});
}
private static void initializeMessageCompression
(final IntegerListPreference mMessageCompression, int[] valueIds, String[] entries, String[] values) {
private static void initializeMessageCompression(
final IntegerListPreference mMessageCompression,
int[] valueIds, String[] entries, String[] values) {
mMessageCompression.setEntries(entries);
mMessageCompression.setEntryValues(values);
mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression());
@ -375,4 +378,4 @@ public class PreferencesActivity extends PreferenceActivity {
}
});
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -17,17 +17,6 @@
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.net.Uri;
import android.os.Bundle;
@ -39,6 +28,16 @@ import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
import java.util.Date;
public class SelectSecretKeyFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
@ -46,9 +45,9 @@ public class SelectSecretKeyFragment extends ListFragment implements
private SelectSecretKeyActivity mActivity;
private SelectKeyCursorAdapter mAdapter;
private ListView mListView;
private boolean mFilterCertify;
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.
long now = new Date().getTime() / 1000;
String[] projection = new String[] {
String[] projection = new String[]{
KeyRings._ID,
KeyRings.MASTER_KEY_ID,
UserIds.USER_ID,

View File

@ -17,6 +17,16 @@
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.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Id;
@ -24,21 +34,6 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
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 {
private TextView mKeyUserId;
@ -106,7 +101,10 @@ public class SelectSecretKeyLayoutFragment extends Fragment {
mKeyUserIdRest.setVisibility(View.GONE);
}
} 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);
mKeyUserIdRest.setVisibility(View.GONE);
}

View File

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

View File

@ -29,7 +29,6 @@ import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
@ -88,7 +87,7 @@ public class ViewKeyActivity extends ActionBarActivity {
// given valid /public/ query
long rowId = ProviderHelper.getRowId(this, getIntent().getData());
// 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();
mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, mDataUri);
@ -124,7 +123,7 @@ public class ViewKeyActivity extends ActionBarActivity {
return true;
case R.id.menu_key_view_export_file:
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;
case R.id.menu_key_view_share_default_fingerprint:
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
Toast.makeText(ViewKeyActivity.this,
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();
} else {
setResult(RESULT_CANCELED);

View File

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

View File

@ -42,6 +42,8 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.util.Log;
import com.beardedhen.androidbootstrap.BootstrapButton;
import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
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.widget.ListView;
import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
@ -52,7 +51,7 @@ import java.util.Date;
public class ViewKeyMainFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor>{
LoaderManager.LoaderCallbacks<Cursor> {
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
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
// right here, so why not.
mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
@ -143,7 +142,10 @@ public class ViewKeyMainFragment extends Fragment implements
mActionEdit.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
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);
startActivityForResult(editIntent, 0);
}
@ -188,21 +190,29 @@ public class ViewKeyMainFragment extends Fragment implements
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};
static final int KEYRING_INDEX_ID = 0;
static final int KEYRING_INDEX_MASTER_KEY_ID = 1;
static final int KEYRING_INDEX_USER_ID = 2;
static final String[] USER_IDS_PROJECTION = new String[]{ KeychainContract.UserIds._ID, KeychainContract.UserIds.USER_ID,
KeychainContract.UserIds.RANK, "verified" };
static final String[] USER_IDS_PROJECTION =
new String[]{KeychainContract.UserIds._ID, KeychainContract.UserIds.USER_ID,
KeychainContract.UserIds.RANK, };
// not the main user id
static final String USER_IDS_SELECTION = KeychainDatabase.Tables.USER_IDS + "." + KeychainContract.UserIds.RANK + " > 0 ";
static final String USER_IDS_SORT_ORDER = KeychainContract.UserIds.USER_ID + " COLLATE LOCALIZED ASC";
static final String USER_IDS_SELECTION =
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,
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_PROJECTION =
new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID,
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 int KEYS_INDEX_ID = 0;
static final int KEYS_INDEX_KEY_ID = 1;
@ -285,7 +295,8 @@ public class ViewKeyMainFragment extends Fragment implements
} else {
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));
}
@ -295,7 +306,8 @@ public class ViewKeyMainFragment extends Fragment implements
} else {
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));
}
@ -323,18 +335,56 @@ public class ViewKeyMainFragment extends Fragment implements
private SpannableStringBuilder colorizeFingerprint(String 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
for (int i = 0; i < fingerprint.length(); i += 5) {
int minFingLength = Math.min(i + 4, fingerprint.length());
String fourChars = fingerprint.substring(i, minFingLength);
int raw = Integer.parseInt(fourChars, 16);
byte[] bytes = {(byte) ((raw >> 8) & 0xff - 128), (byte) (raw & 0xff - 128)};
int[] color = OtherHelper.getRgbForData(bytes);
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
// and then converting that int to hex to use as a color
fcs = new ForegroundColorSpan(
Color.parseColor(String.format("#%06X", (0xFFFFFF & fourChars.hashCode()))));
sb.setSpan(fcs, i, minFingLength, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
// we cannot change black by multiplication, so adjust it to an almost-black grey,
// which will then be brightened to the minimal brightness level
if (r == 0 && g == 0 && b == 0) {
r = 1;
g = 1;
b = 1;
}
// Convert rgb to brightness
double brightness = 0.2126 * r + 0.7152 * g + 0.0722 * b;
// If a color is too dark to be seen on black,
// then brighten it up to a minimal brightness.
if (brightness < 80) {
double factor = 80.0 / brightness;
r = Math.min(255, (int) (r * factor));
g = Math.min(255, (int) (g * factor));
b = Math.min(255, (int) (b * factor));
// If it is too light, then darken it to a respective maximal brightness.
} else if (brightness > 180) {
double factor = 180.0 / brightness;
r = (int) (r * factor);
g = (int) (g * factor);
b = (int) (b * factor);
}
// Create a foreground color with the 3 digest integers as RGB
// and then converting that int to hex to use as a color
sb.setSpan(new ForegroundColorSpan(Color.rgb(r, g, b)),
i, spanEnd, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
} catch (Exception e) {
Log.e(Constants.TAG, "Colorization failed", e);
// if anything goes wrong, then just display the fingerprint without colour,
// instead of partially correct colour or wrong colours
return new SpannableStringBuilder(fingerprint);
}
return sb;
@ -377,5 +427,4 @@ public class ViewKeyMainFragment extends Fragment implements
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.
* Concept found at:
* https://stackoverflow.com/questions/19593577/how-to-handle-errors-in-custom-asynctaskloader
*
* @param <T> - Typ of the result which is wrapped
*/
public class AsyncTaskResultWrapper <T>{
public class AsyncTaskResultWrapper<T> {
private final T result;
private final Exception error;
private final T mResult;
private final Exception mError;
public AsyncTaskResultWrapper(T result, Exception error){
this.result = result;
this.error = error;
public AsyncTaskResultWrapper(T result, Exception error) {
this.mResult = result;
this.mError = error;
}
public T getResult() {
return result;
return mResult;
}
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.text.Spannable;
import android.text.style.ForegroundColorSpan;
import org.sufficientlysecure.keychain.R;
import java.util.regex.Matcher;

View File

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

View File

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

View File

@ -17,10 +17,8 @@
package org.sufficientlysecure.keychain.ui.adapter;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPUtil;
@ -29,22 +27,26 @@ import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import java.io.BufferedInputStream;
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 NonPgpPart extends Exception {
private int count;
private int mCount;
public NonPgpPart(int count) {
this.count = count;
this.mCount = count;
}
public int getCount() {
return count;
return mCount;
}
}
@ -52,8 +54,8 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
InputData mInputData;
ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>();
AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper;
ArrayList<ImportKeysListEntry> mData = new ArrayList<ImportKeysListEntry>();
AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper;
public ImportKeysListLoader(Context context, InputData inputData) {
super(context);
@ -64,16 +66,16 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
@Override
public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(data, null);
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mData, null);
if (mInputData == null) {
Log.e(Constants.TAG, "Input data is null!");
return entryListWrapper;
return mEntryListWrapper;
}
generateListOfKeyrings(mInputData);
return entryListWrapper;
return mEntryListWrapper;
}
@Override
@ -101,7 +103,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
/**
* Reads all PGPKeyRing objects from input
*
*
* @param inputData
* @return
*/
@ -141,25 +143,25 @@ public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper
}
} catch (Exception 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;
}
if(isEmpty) {
if (isEmpty) {
Log.e(Constants.TAG, "File has no content!", new FileHasNoContent());
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>
(data, new FileHasNoContent());
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>
(mData, new FileHasNoContent());
}
if(nonPgpCounter > 0) {
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>
(data, new NonPgpPart(nonPgpCounter));
if (nonPgpCounter > 0) {
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>
(mData, new NonPgpPart(nonPgpCounter));
}
}
private void addToData(PGPKeyRing 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.support.v4.content.AsyncTaskLoader;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.HkpKeyServer;
import org.sufficientlysecure.keychain.util.KeyServer;
@ -27,14 +26,15 @@ import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList;
public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
public class ImportKeysListServerLoader
extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
Context mContext;
String mServerQuery;
String mKeyServer;
private ArrayList<ImportKeysListEntry> entryList = new ArrayList<ImportKeysListEntry>();
private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper;
private ArrayList<ImportKeysListEntry> mEntryList = new ArrayList<ImportKeysListEntry>();
private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper;
public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) {
super(context);
@ -46,16 +46,16 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultW
@Override
public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null);
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null);
if (mServerQuery == null) {
Log.e(Constants.TAG, "mServerQuery is null!");
return entryListWrapper;
return mEntryListWrapper;
}
queryServer(mServerQuery, mKeyServer);
return entryListWrapper;
return mEntryListWrapper;
}
@Override
@ -89,18 +89,19 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultW
try {
ArrayList<ImportKeysListEntry> searchResult = server.search(query);
mEntryList.clear();
// add result to data
entryList.addAll(searchResult);
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null);
mEntryList.addAll(searchResult);
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null);
} catch (KeyServer.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) {
Log.e(Constants.TAG, "QueryException", e);
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e);
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
} catch (KeyServer.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;
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.widget.ArrayAdapter;
import java.util.*;
public class KeyValueSpinnerAdapter extends ArrayAdapter<String> {
private final HashMap<Integer, String> mData;
private final int[] mKeys;
@ -98,4 +94,4 @@ public class KeyValueSpinnerAdapter extends ArrayAdapter<String> {
}
return -1;
}
}
}

View File

@ -17,12 +17,6 @@
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.database.Cursor;
import android.view.LayoutInflater;
@ -31,7 +25,11 @@ import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {
@ -46,11 +44,11 @@ public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {
private int mIndexProjectionValid;
private int mIndexProjectionAvailable;
public final static String PROJECTION_ROW_AVAILABLE = "available";
public final static String PROJECTION_ROW_VALID = "valid";
public static final String PROJECTION_ROW_AVAILABLE = "available";
public static final String PROJECTION_ROW_VALID = "valid";
public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView,
int keyType) {
int keyType) {
super(context, c, flags);
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
* performance comparison see http://stackoverflow.com/a/17999582
*
*
* @param 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;
import android.content.Context;
@ -19,12 +36,12 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
private final Class<?> mClss;
private final Bundle mArgs;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
TabInfo(Class<?> mClss, Bundle mArgs) {
this.mClss = mClss;
this.mArgs = mArgs;
}
}
@ -54,7 +71,7 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.
@Override
public Fragment getItem(int 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) {
@ -81,4 +98,4 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar.
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
}
}

View File

@ -17,10 +17,6 @@
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.database.Cursor;
import android.support.v4.widget.CursorAdapter;
@ -29,6 +25,9 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
public class ViewKeyKeysAdapter extends CursorAdapter {
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
* performance comparison see http://stackoverflow.com/a/17999582
*
*
* @param cursor
*/
private void initIndex(Cursor cursor) {

View File

@ -17,9 +17,6 @@
package org.sufficientlysecure.keychain.ui.adapter;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import android.content.Context;
import android.database.Cursor;
import android.support.v4.widget.CursorAdapter;
@ -27,6 +24,8 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
public class ViewKeyUserIdsAdapter extends CursorAdapter {
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
* performance comparison see http://stackoverflow.com/a/17999582
*
*
* @param cursor
*/
private void initIndex(Cursor cursor) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -24,7 +24,7 @@ import android.widget.ListView;
/**
* Automatically calculate height of ListView based on contained items. This enables to put this
* ListView into a ScrollView without messing up.
*
* <p/>
* from
* http://stackoverflow.com/questions/2419246/how-do-i-create-a-listview-thats-not-in-a-scrollview-
* or-has-the-scrollview-dis
@ -52,4 +52,4 @@ public class FixedListView extends ListView {
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
* arrays for entry values, the arrays should be regular string arrays containing valid integer
* values.
*
*
* @author Rodrigo Damazio
*/
public class IntegerListPreference extends ListPreference {

View File

@ -16,20 +16,7 @@
package org.sufficientlysecure.keychain.ui.widget;
import java.text.DateFormat;
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.annotation.TargetApi;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.content.Context;
@ -39,13 +26,17 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.DatePicker;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.*;
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 {
private PGPSecretKey mKey;
@ -63,7 +54,8 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
GregorianCalendar mExpiryDate;
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) {
// Note: Ignore results after the first one - android sends multiples.
if (mDatePickerResultCount++ == 0) {
@ -110,6 +102,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
setExpiryDate(null);
mExpiryDateButton.setOnClickListener(new OnClickListener() {
@TargetApi(11)
public void onClick(View v) {
GregorianCalendar date = mExpiryDate;
if (date == null) {
@ -137,16 +130,18 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
});
// 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.
dialog.getDatePicker().setCalendarViewShown(false);
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
if ( dialog != null && mCreatedDate != null ) {
dialog.getDatePicker().setMinDate(mCreatedDate.getTime().getTime()+ DateUtils.DAY_IN_MILLIS);
if (dialog != null && mCreatedDate != null) {
dialog.getDatePicker()
.setMinDate(
mCreatedDate.getTime().getTime() + DateUtils.DAY_IN_MILLIS);
} else {
//When created date isn't available
dialog.getDatePicker().setMinDate(date.getTime().getTime()+ DateUtils.DAY_IN_MILLIS);
dialog.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 {
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);
}
//Set permanent title.
public void setTitle(CharSequence title) {
super.setTitle(getContext().getString(R.string.expiry_date_dialog_title));

View File

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

View File

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

View File

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

View File

@ -16,21 +16,22 @@
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.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Patterns;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.*;
import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ContactHelper;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class UserIdEditor extends LinearLayout implements Editor, OnClickListener {
private EditorListener mEditorListener = null;
@ -40,14 +41,6 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
private AutoCompleteTextView mEmail;
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 {
static final long serialVersionUID = 0xf812773343L;
@ -109,8 +102,33 @@ public class UserIdEditor extends LinearLayout implements Editor, OnClickListene
mEmail.setAdapter(
new ArrayAdapter<String>
(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();
}
@ -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 email = ("" + mEmail.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;
if (comment.length() > 0) {
userId += " (" + comment + ")";

View File

@ -17,13 +17,14 @@
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.openpgp.PGPEncryptedData;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import android.annotation.SuppressLint;
import android.app.Activity;
import java.util.HashMap;
@SuppressLint("UseSparseArrays")
public class AlgorithmNames {

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