diff --git a/.gitignore b/.gitignore index c4f2c8ad0..74d516d1e 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,8 @@ pom.xml.* #OS Specific [Tt]humbs.db + + +#Lint output +OpenPGP-Keychain/lint-report.html +OpenPGP-Keychain/lint-report_files/* \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 54db1a965..df700368c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/OpenPGP-Keychain/build.gradle b/OpenPGP-Keychain/build.gradle index 6338774eb..04ee46715 100644 --- a/OpenPGP-Keychain/build.gradle +++ b/OpenPGP-Keychain/build.gradle @@ -57,5 +57,7 @@ android { // Do not abort build if lint finds errors lintOptions { abortOnError false + htmlReport true + htmlOutput file("lint-report.html") } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java index 19dfccbde..245c5fda1 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java @@ -16,6 +16,17 @@ 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,16 +37,6 @@ 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; @@ -115,7 +116,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(activity, KeychainIntentService.class); intent.setAction(KeychainIntentService.ACTION_EXPORT_KEYRING); @@ -135,7 +136,12 @@ public class ExportHelper { // Message is received after exporting is done in ApgService 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) { // handle messages by standard ApgHandler first super.handleMessage(message); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java index 34d90a17f..292b5bf3d 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/OtherHelper.java @@ -17,6 +17,9 @@ package org.sufficientlysecure.keychain.helper; +import java.security.DigestException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Iterator; 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; + } + } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index 138e54f71..3ce9fa7c5 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -42,6 +42,7 @@ import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.util.HkpKeyServer; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException; +import org.sufficientlysecure.keychain.util.KeychainServiceListener; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; @@ -50,15 +51,25 @@ import android.os.Bundle; import android.os.Environment; 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); @@ -188,8 +199,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 +211,11 @@ public class PgpImportExport { if (publicKeyRing != null) { publicKeyRing.encode(arOutStream); } + + if(mKeychainServiceListener.hasServiceStopped()){ + arOutStream.close(); + return null; + } } arOutStream.close(); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 93238349d..23f489d35 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -56,6 +56,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.util.HkpKeyServer; import org.sufficientlysecure.keychain.util.InputData; +import org.sufficientlysecure.keychain.util.KeychainServiceListener; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; @@ -73,7 +74,7 @@ import android.os.RemoteException; * 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"; @@ -712,10 +713,15 @@ public class KeychainIntentService extends IntentService implements ProgressDial 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); @@ -903,4 +909,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; + } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index 4950126dd..95c0f7f3a 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -29,6 +29,7 @@ import android.support.v4.content.Loader; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.format.DateFormat; +import android.text.style.BackgroundColorSpan; import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.View; @@ -40,6 +41,7 @@ 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.ProviderHelper; @@ -47,6 +49,8 @@ import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter; import org.sufficientlysecure.keychain.util.Log; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Date; @@ -305,18 +309,40 @@ 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 minFingLength = Math.min(i + 4, fingerprint.length()); + String fourChars = fingerprint.substring(i, minFingLength); - // 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); - // 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); + // 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 + sb.setSpan(new ForegroundColorSpan(Color.rgb(color[0], color[1], color[2])), + 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; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java index 65461cb4f..9f25fac42 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java @@ -30,6 +30,7 @@ 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; @@ -110,6 +111,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) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java new file mode 100644 index 000000000..0d7513057 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeychainServiceListener.java @@ -0,0 +1,5 @@ +package org.sufficientlysecure.keychain.util; + +public interface KeychainServiceListener { + boolean hasServiceStopped(); +} diff --git a/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml b/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml index c56ba130e..a974f6ec0 100644 --- a/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml +++ b/OpenPGP-Keychain/src/main/res/layout/decrypt_activity.xml @@ -5,16 +5,11 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - + android:fillViewport="true" + android:orientation="vertical"> - diff --git a/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml b/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml index 3030d6bae..a8d1dc674 100644 --- a/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml +++ b/OpenPGP-Keychain/src/main/res/layout/edit_key_user_id_item.xml @@ -71,7 +71,8 @@ android:id="@+id/comment" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_weight="1" /> + android:layout_weight="1" + android:inputType="text"/> diff --git a/OpenPGP-Keychain/src/main/res/layout/key_server_editor.xml b/OpenPGP-Keychain/src/main/res/layout/key_server_editor.xml index 058a43eaf..950978a0e 100644 --- a/OpenPGP-Keychain/src/main/res/layout/key_server_editor.xml +++ b/OpenPGP-Keychain/src/main/res/layout/key_server_editor.xml @@ -13,7 +13,7 @@ diff --git a/OpenPGP-Keychain/src/main/res/layout/key_server_preference.xml b/OpenPGP-Keychain/src/main/res/layout/key_server_preference.xml index 4a09e4240..eddbe3cbf 100644 --- a/OpenPGP-Keychain/src/main/res/layout/key_server_preference.xml +++ b/OpenPGP-Keychain/src/main/res/layout/key_server_preference.xml @@ -14,7 +14,7 @@ android:orientation="horizontal" > Für diese Benutzer-IDs wurden keine öffentlichen Schlüssel gefunden: Für diese Benutzer-IDs existieren mehrere öffentliche Schlüssel: Bitte die Liste der Empfänger überprüfen! - 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. + 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. Über QR Code teilen Mit \'Weiter\' durch alle QR-Codes gehen und diese nacheinander scannen. diff --git a/OpenPGP-Keychain/src/main/res/values/strings.xml b/OpenPGP-Keychain/src/main/res/values/strings.xml index ca54db266..1c7ead403 100644 --- a/OpenPGP-Keychain/src/main/res/values/strings.xml +++ b/OpenPGP-Keychain/src/main/res/values/strings.xml @@ -317,8 +317,8 @@ - done. - cancel + Done. + Cancel saving… importing… exporting… diff --git a/README.md b/README.md index 4b997c59f..8954bdcda 100644 --- a/README.md +++ b/README.md @@ -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/ ### 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) -* Go to Settings (or Preferences in Mac OS X) > 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 - or you can directly run checkstyle via cli with .tools/checkstyle. Make sure it's executable first. + +####Linux +1. Paste the `tools/checkstyle.xml` file to `~/.AndroidStudioPreview/config/codestyles/` +2. Go to 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 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\\.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 OpenPGP Kechain is licensed under GPLv3+.