Merge remote-tracking branch 'origin/master'

Conflicts:
	OpenPGP-Keychain/src/main/res/menu/key_list_secret.xml
This commit is contained in:
Vincent Breitmoser 2014-03-13 13:40:47 +01:00
commit 9a1ce093bf
18 changed files with 149 additions and 49 deletions

5
.gitignore vendored
View File

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

View File

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

View File

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

View File

@ -16,6 +16,17 @@
package org.sufficientlysecure.keychain.helper; package org.sufficientlysecure.keychain.helper;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.support.v7.app.ActionBarActivity;
import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
@ -26,16 +37,6 @@ import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.support.v7.app.ActionBarActivity;
import android.widget.Toast;
public class ExportHelper { public class ExportHelper {
protected FileDialogFragment mFileDialog; protected FileDialogFragment mFileDialog;
protected String mExportFilename; protected String mExportFilename;
@ -115,7 +116,7 @@ public class ExportHelper {
Log.d(Constants.TAG, "exportKeys started"); Log.d(Constants.TAG, "exportKeys started");
// Send all information needed to service to export key in other thread // Send all information needed to service to export key in other thread
Intent intent = new Intent(activity, KeychainIntentService.class); final Intent intent = new Intent(activity, KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_EXPORT_KEYRING); intent.setAction(KeychainIntentService.ACTION_EXPORT_KEYRING);
@ -135,7 +136,12 @@ public class ExportHelper {
// Message is received after exporting is done in ApgService // Message is received after exporting is done in ApgService
KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(activity, KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(activity,
activity.getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL) { activity.getString(R.string.progress_exporting), ProgressDialog.STYLE_HORIZONTAL, true, new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
activity.stopService(intent);
}
}) {
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard ApgHandler first // handle messages by standard ApgHandler first
super.handleMessage(message); super.handleMessage(message);

View File

@ -17,6 +17,9 @@
package org.sufficientlysecure.keychain.helper; package org.sufficientlysecure.keychain.helper;
import java.security.DigestException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
@ -58,4 +61,23 @@ 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

@ -42,6 +42,7 @@ import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import org.sufficientlysecure.keychain.util.HkpKeyServer; import org.sufficientlysecure.keychain.util.HkpKeyServer;
import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException; import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException;
import org.sufficientlysecure.keychain.util.KeychainServiceListener;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
@ -50,15 +51,25 @@ import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
public class PgpImportExport { public class PgpImportExport {
private Context mContext; private Context mContext;
private ProgressDialogUpdater mProgress; private ProgressDialogUpdater mProgress;
private KeychainServiceListener mKeychainServiceListener;
public PgpImportExport(Context context, ProgressDialogUpdater progress) { public PgpImportExport(Context context, ProgressDialogUpdater progress) {
super(); super();
this.mContext = context; this.mContext = context;
this.mProgress = progress; this.mProgress = progress;
} }
public PgpImportExport(Context context, ProgressDialogUpdater progress, KeychainServiceListener keychainListener){
super();
this.mContext = context;
this.mProgress = progress;
this.mKeychainServiceListener = keychainListener;
}
public void updateProgress(int message, int current, int total) { public void updateProgress(int message, int current, int total) {
if (mProgress != null) { if (mProgress != null) {
mProgress.setProgress(message, current, total); mProgress.setProgress(message, current, total);
@ -188,8 +199,10 @@ public class PgpImportExport {
if (secretKeyRing != null) { if (secretKeyRing != null) {
secretKeyRing.encode(arOutStream); secretKeyRing.encode(arOutStream);
} }
// Else if it's a public key get the PGPPublicKeyRing if(mKeychainServiceListener.hasServiceStopped()){
// and encode that to the output arOutStream.close();
return null;
}
} else { } else {
updateProgress(i * 100 / rowIdsSize, 100); updateProgress(i * 100 / rowIdsSize, 100);
PGPPublicKeyRing publicKeyRing = PGPPublicKeyRing publicKeyRing =
@ -198,6 +211,11 @@ public class PgpImportExport {
if (publicKeyRing != null) { if (publicKeyRing != null) {
publicKeyRing.encode(arOutStream); publicKeyRing.encode(arOutStream);
} }
if(mKeychainServiceListener.hasServiceStopped()){
arOutStream.close();
return null;
}
} }
arOutStream.close(); arOutStream.close();

View File

@ -56,6 +56,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import org.sufficientlysecure.keychain.util.HkpKeyServer; import org.sufficientlysecure.keychain.util.HkpKeyServer;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.KeychainServiceListener;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
@ -73,7 +74,7 @@ import android.os.RemoteException;
* data from the activities or other apps, queues these intents, executes them, and stops itself * data from the activities or other apps, queues these intents, executes them, and stops itself
* after doing them. * after doing them.
*/ */
public class KeychainIntentService extends IntentService implements ProgressDialogUpdater { public class KeychainIntentService extends IntentService implements ProgressDialogUpdater, KeychainServiceListener {
/* extras that can be given by intent */ /* extras that can be given by intent */
public static final String EXTRA_MESSENGER = "messenger"; public static final String EXTRA_MESSENGER = "messenger";
@ -712,10 +713,15 @@ public class KeychainIntentService extends IntentService implements ProgressDial
Bundle resultData; Bundle resultData;
PgpImportExport pgpImportExport = new PgpImportExport(this, this); PgpImportExport pgpImportExport = new PgpImportExport(this, this, this);
resultData = pgpImportExport resultData = pgpImportExport
.exportKeyRings(keyRingRowIds, keyType, outStream); .exportKeyRings(keyRingRowIds, keyType, outStream);
if(mIsCanceled){
boolean isDeleted = new File(outputFile).delete();
}
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) { } catch (Exception e) {
sendErrorToHandler(e); sendErrorToHandler(e);
@ -903,4 +909,9 @@ public class KeychainIntentService extends IntentService implements ProgressDial
public void setProgress(int progress, int max) { public void setProgress(int progress, int max) {
setProgress(null, progress, max); setProgress(null, progress, max);
} }
@Override
public boolean hasServiceStopped() {
return mIsCanceled;
}
} }

View File

@ -29,6 +29,7 @@ import android.support.v4.content.Loader;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.format.DateFormat; import android.text.format.DateFormat;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -40,6 +41,7 @@ import com.beardedhen.androidbootstrap.BootstrapButton;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
@ -47,6 +49,8 @@ import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter;
import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter; import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date; import java.util.Date;
@ -305,18 +309,40 @@ public class ViewKeyMainFragment extends Fragment implements
private SpannableStringBuilder colorizeFingerprint(String fingerprint) { private SpannableStringBuilder colorizeFingerprint(String fingerprint) {
SpannableStringBuilder sb = new SpannableStringBuilder(fingerprint); SpannableStringBuilder sb = new SpannableStringBuilder(fingerprint);
ForegroundColorSpan fcs = new ForegroundColorSpan(Color.BLACK); try {
// for each 4 characters of the fingerprint + 1 space // for each 4 characters of the fingerprint + 1 space
for (int i = 0; i < fingerprint.length(); i += 5) { for (int i = 0; i < fingerprint.length(); i += 5) {
int minFingLength = Math.min(i + 4, fingerprint.length()); int minFingLength = Math.min(i + 4, fingerprint.length());
String fourChars = fingerprint.substring(i, minFingLength); String fourChars = fingerprint.substring(i, minFingLength);
// Create a foreground color by converting the 4 fingerprint chars to an int hashcode int raw = Integer.parseInt(fourChars, 16);
byte[] bytes = {(byte) ((raw >> 8) & 0xff - 128), (byte) (raw & 0xff - 128)};
int[] color = OtherHelper.getRgbForData(bytes);
// Convert rgb to brightness
int brightness = (int) (0.2126*color[0] + 0.7152*color[1] + 0.0722*color[2]);
// Detect dark colors and invert their background to white to make them more distinguishable
if (brightness < 40) {
sb.setSpan(new BackgroundColorSpan(Color.WHITE),
i, minFingLength, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
// Detect bright colors and invert their background to black to make them more distinguishable
} else if (brightness > 210) {
sb.setSpan(new BackgroundColorSpan(Color.BLACK),
i, minFingLength, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
// Create a foreground color with the 3 digest integers as RGB
// and then converting that int to hex to use as a color // and then converting that int to hex to use as a color
fcs = new ForegroundColorSpan( sb.setSpan(new ForegroundColorSpan(Color.rgb(color[0], color[1], color[2])),
Color.parseColor(String.format("#%06X", (0xFFFFFF & fourChars.hashCode())))); i, minFingLength, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
sb.setSpan(fcs, i, minFingLength, Spannable.SPAN_INCLUSIVE_INCLUSIVE); }
} catch (Exception e) {
Log.e(Constants.TAG, "Colorization failed", e);
// if anything goes wrong, then just display the fingerprint without colour,
// instead of partially correct colour or wrong colours
return new SpannableStringBuilder(fingerprint);
} }
return sb; return sb;

View File

@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.Choice; import org.sufficientlysecure.keychain.util.Choice;
import android.annotation.TargetApi;
import android.app.DatePickerDialog; import android.app.DatePickerDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
@ -110,6 +111,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener {
setExpiryDate(null); setExpiryDate(null);
mExpiryDateButton.setOnClickListener(new OnClickListener() { mExpiryDateButton.setOnClickListener(new OnClickListener() {
@TargetApi(11)
public void onClick(View v) { public void onClick(View v) {
GregorianCalendar date = mExpiryDate; GregorianCalendar date = mExpiryDate;
if (date == null) { if (date == null) {

View File

@ -0,0 +1,5 @@
package org.sufficientlysecure.keychain.util;
public interface KeychainServiceListener {
boolean hasServiceStopped();
}

View File

@ -5,17 +5,12 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fillViewport="true" android:fillViewport="true"
android:orientation="vertical"> android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -73,7 +68,6 @@
android:layout_gravity="left" android:layout_gravity="left"
android:text="@string/label_main_user_id" android:text="@string/label_main_user_id"
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_alignTop="@+id/linearLayout"
android:layout_toRightOf="@+id/relativeLayout" /> android:layout_toRightOf="@+id/relativeLayout" />
<TextView <TextView
@ -206,7 +200,6 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>
</LinearLayout>
<include layout="@layout/drawer_list" /> <include layout="@layout/drawer_list" />

View File

@ -71,7 +71,8 @@
android:id="@+id/comment" android:id="@+id/comment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" /> android:layout_weight="1"
android:inputType="text"/>
</TableRow> </TableRow>
</TableLayout> </TableLayout>

View File

@ -13,7 +13,7 @@
<EditText <EditText
android:id="@+id/server" android:id="@+id/server"
android:layout_width="match_parent" android:layout_width="0dip"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:inputType="textUri" /> android:inputType="textUri" />

View File

@ -14,7 +14,7 @@
android:orientation="horizontal" > android:orientation="horizontal" >
<RelativeLayout <RelativeLayout
android:layout_width="wrap_content" android:layout_width="0dip"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="6sp" android:layout_marginBottom="6sp"
android:layout_marginLeft="16sp" android:layout_marginLeft="16sp"

View File

@ -5,7 +5,7 @@
<item <item
android:id="@+id/menu_key_view_share" android:id="@+id/menu_key_view_share"
android:icon="@drawable/ic_action_share" android:icon="@drawable/ic_action_share"
app:showAsAction="always" app:showAsAction="ifRoom"
android:title="@string/menu_share"> android:title="@string/menu_share">
<menu> <menu>
<item <item

View File

@ -356,7 +356,7 @@
<string name="api_select_pub_keys_missing_text">Für diese Benutzer-IDs wurden keine öffentlichen Schlüssel gefunden:</string> <string name="api_select_pub_keys_missing_text">Für diese Benutzer-IDs wurden keine öffentlichen Schlüssel gefunden:</string>
<string name="api_select_pub_keys_dublicates_text">Für diese Benutzer-IDs existieren mehrere öffentliche Schlüssel:</string> <string name="api_select_pub_keys_dublicates_text">Für diese Benutzer-IDs existieren mehrere öffentliche Schlüssel:</string>
<string name="api_select_pub_keys_text">Bitte die Liste der Empfänger überprüfen!</string> <string name="api_select_pub_keys_text">Bitte die Liste der Empfänger überprüfen!</string>
<string name="api_error_wrong_signature">Signaturüberprüfung fehlgeschlagen! Haben Sie diese App von einer anderen Quelle installiert? Wenn Sie eine Attacke ausschliessen können, sollten Sie die Registrierung der App in OpenKeychain widerrufen und die App erneut registrieren.</string> <string name="api_error_wrong_signature">Signaturüberprüfung fehlgeschlagen! Haben Sie diese App von einer anderen Quelle installiert? Wenn Sie eine Attacke ausschließen können, sollten Sie die Registrierung der App in OpenKeychain widerrufen und die App erneut registrieren.</string>
<!--Share--> <!--Share-->
<string name="share_qr_code_dialog_title">Über QR Code teilen</string> <string name="share_qr_code_dialog_title">Über QR Code teilen</string>
<string name="share_qr_code_dialog_start">Mit \'Weiter\' durch alle QR-Codes gehen und diese nacheinander scannen.</string> <string name="share_qr_code_dialog_start">Mit \'Weiter\' durch alle QR-Codes gehen und diese nacheinander scannen.</string>

View File

@ -317,8 +317,8 @@
</plurals> </plurals>
<!-- progress dialogs, usually ending in '…' --> <!-- progress dialogs, usually ending in '…' -->
<string name="progress_done">done.</string> <string name="progress_done">Done.</string>
<string name="progress_cancel">cancel</string> <string name="progress_cancel">Cancel</string>
<string name="progress_saving">saving…</string> <string name="progress_saving">saving…</string>
<string name="progress_importing">importing…</string> <string name="progress_importing">importing…</string>
<string name="progress_exporting">exporting…</string> <string name="progress_exporting">exporting…</string>

View File

@ -156,12 +156,21 @@ See http://source.android.com/source/code-style.html
See http://www.androidpolice.com/2009/11/04/auto-formatting-android-xml-files-with-eclipse/ See http://www.androidpolice.com/2009/11/04/auto-formatting-android-xml-files-with-eclipse/
### Automated syntax check with CheckStyle ### Automated syntax check with CheckStyle
* Paste the tools/checkstyle.xml file to ~/.AndroidStudioPreview/config/codestyles/ (in Linux/Unix)
or ~/Library/Preferences/AndroidStudioPreview/codestyles (in Mac OSX) ####Linux
* Go to Settings (or Preferences in Mac OS X) > Code Style > Java, select OpenPgpChecker, 1. Paste the `tools/checkstyle.xml` file to `~/.AndroidStudioPreview/config/codestyles/`
as well as Code Style > XML and select OpenPgpChecker again. 2. Go to Settings > Code Style > Java, select OpenPgpChecker, as well as Code Style > XML and select OpenPgpChecker again.
* Start code inspection and see the results by selecting Analyze > Inspect Code from Android-Studio 3. Start code inspection and see the results by selecting Analyze > Inspect Code from Android-Studio or you can directly run checkstyle via cli with `.tools/checkstyle`. Make sure it's executable first.
or you can directly run checkstyle via cli with .tools/checkstyle. Make sure it's executable first.
####Mac OSX
1. Paste the `tools/checkstyle.xml` file to `~/Library/Preferences/AndroidStudioPreview/codestyles`
2. Go to Preferences > Code Style > Java, select OpenPgpChecker, as well as Code Style > XML and select OpenPgpChecker again.
3. Start code inspection and see the results by selecting Analyze > Inspect Code from Android-Studio or you can directly run checkstyle via cli with `.tools/checkstyle`. Make sure it's executable first.
####Windows
1. Paste the `tools/checkstyle.xml` file to `C:\Users\<UserName>\.AndroidStudioPreview\config\codestyles`
2. Go to File > Settings > Code Style > Java, select OpenPgpChecker, as well as Code Style > XML and select OpenPgpChecker again.
3. Start code inspection and see the results by selecting Analyze > Inspect Code from Android-Studio.
## Licenses ## Licenses
OpenPGP Kechain is licensed under GPLv3+. OpenPGP Kechain is licensed under GPLv3+.