Added support for PGPony

master
M66B 3 weeks ago
parent d8d7c5bcd3
commit 716262adf8

@ -1029,8 +1029,10 @@ If you want to undo decryption, you can tap on the "close" padlock icon.
*PGP* *PGP*
You'll need to install and configure [OpenKeychain](https://f-droid.org/en/packages/org.sufficientlysecure.keychain/) first. You'll need to install and configure [OpenKeychain](https://f-droid.org/en/packages/org.sufficientlysecure.keychain/) or [PGPony](https://github.com/norsehorse-dev/PGPonyAndroid) first.
FairEmail was tested with OpenKeychain version 5.4. Later versions will most likely be compatible, but earlier versions might not be. FairEmail was tested with OpenKeychain version 5.4 and PGPony 4.1.1. Later versions will most likely be compatible, but earlier versions might not be.
**Note** that you need to select the correct OpenPGP provider on the encryption settings tab page.
[PGPony for Android](https://github.com/norsehorse-dev/PGPonyAndroid) is reported to work too. You can select the PGP provider on the encryption settings tab page. [PGPony for Android](https://github.com/norsehorse-dev/PGPonyAndroid) is reported to work too. You can select the PGP provider on the encryption settings tab page.

@ -3285,8 +3285,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
// Check for inline encryption // Check for inline encryption
boolean iencrypted = HtmlHelper.contains(document, new String[]{ boolean iencrypted = HtmlHelper.contains(document, new String[]{
Helper.PGP_BEGIN_MESSAGE, PgpHelper.PGP_BEGIN_MESSAGE,
Helper.PGP_END_MESSAGE PgpHelper.PGP_END_MESSAGE
}); });
args.putBoolean("inline_encrypted", iencrypted); args.putBoolean("inline_encrypted", iencrypted);

@ -1153,6 +1153,9 @@ public class ApplicationEx extends Application
if ("none".equals(onclose)) if ("none".equals(onclose))
editor.remove("onclose"); editor.remove("onclose");
if (BuildConfig.DEBUG)
editor.remove("openpgp_provider");
editor.apply(); editor.apply();
} }

@ -4432,14 +4432,10 @@ public class FragmentCompose extends FragmentBase {
@Override @Override
protected void onException(Bundle args, Throwable ex) { protected void onException(Bundle args, Throwable ex) {
if (ex instanceof IllegalArgumentException if (!PgpHelper.isOpenKeychainInstalled(getContext())) {
|| ex instanceof GeneralSecurityException /* InvalidKeyException */) { String text = getString(R.string.title_no_openpgp);
Log.i(ex); text += "\n" + Log.formatThrowable(ex, false);
Helper.setSnackbarOptions( Snackbar snackbar = Helper.setSnackbarOptions(Snackbar.make(view, text, Snackbar.LENGTH_INDEFINITE));
Snackbar.make(view, new ThrowableWrapper(ex).getSafeMessage(), Snackbar.LENGTH_LONG))
.show();
} else if (ex instanceof OperationCanceledException) {
Snackbar snackbar = Helper.setSnackbarOptions(Snackbar.make(view, R.string.title_no_openpgp, Snackbar.LENGTH_INDEFINITE));
snackbar.setAction(R.string.title_fix, new View.OnClickListener() { snackbar.setAction(R.string.title_fix, new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -4447,7 +4443,14 @@ public class FragmentCompose extends FragmentBase {
Helper.viewFAQ(v.getContext(), 12); Helper.viewFAQ(v.getContext(), 12);
} }
}); });
Helper.setSnackbarLines(snackbar, 7);
snackbar.show(); snackbar.show();
} else if (ex instanceof IllegalArgumentException
|| ex instanceof GeneralSecurityException /* InvalidKeyException */) {
Log.i(ex);
Helper.setSnackbarOptions(
Snackbar.make(view, new ThrowableWrapper(ex).getSafeMessage(), Snackbar.LENGTH_LONG))
.show();
} else } else
Log.unexpectedError(getParentFragmentManager(), ex); Log.unexpectedError(getParentFragmentManager(), ex);
} }

@ -9974,11 +9974,11 @@ public class FragmentMessages extends FragmentBase
// https://tools.ietf.org/html/rfc4880#section-6.2 // https://tools.ietf.org/html/rfc4880#section-6.2
String html = Helper.readText(file); String html = Helper.readText(file);
String body = HtmlHelper.fromHtml(html, context).toString(); String body = HtmlHelper.fromHtml(html, context).toString();
int begin = body.indexOf(Helper.PGP_BEGIN_MESSAGE); int begin = body.indexOf(PgpHelper.PGP_BEGIN_MESSAGE);
int end = body.indexOf(Helper.PGP_END_MESSAGE); int end = body.indexOf(PgpHelper.PGP_END_MESSAGE);
if (begin >= 0 && begin < end) { if (begin >= 0 && begin < end) {
String[] lines = body String[] lines = body
.substring(begin, end + Helper.PGP_END_MESSAGE.length()) .substring(begin, end + PgpHelper.PGP_END_MESSAGE.length())
.split("\\r?\\n"); .split("\\r?\\n");
List<String> disarmored = new ArrayList<>(); List<String> disarmored = new ArrayList<>();
@ -10269,13 +10269,10 @@ public class FragmentMessages extends FragmentBase
if (auto) if (auto)
return; return;
if (ex instanceof IllegalArgumentException) { if (!PgpHelper.isOpenKeychainInstalled(getContext())) {
Log.i(ex); String text = getString(R.string.title_no_openpgp);
Helper.setSnackbarOptions( text += "\n" + Log.formatThrowable(ex, false);
Snackbar.make(view, ex.getMessage(), Snackbar.LENGTH_LONG)) Snackbar snackbar = Helper.setSnackbarOptions(Snackbar.make(view, text, Snackbar.LENGTH_INDEFINITE));
.show();
} else if (ex instanceof OperationCanceledException) {
Snackbar snackbar = Helper.setSnackbarOptions(Snackbar.make(view, R.string.title_no_openpgp, Snackbar.LENGTH_INDEFINITE));
snackbar.setAction(R.string.title_fix, new View.OnClickListener() { snackbar.setAction(R.string.title_fix, new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -10283,7 +10280,13 @@ public class FragmentMessages extends FragmentBase
Helper.viewFAQ(v.getContext(), 12); Helper.viewFAQ(v.getContext(), 12);
} }
}); });
Helper.setSnackbarLines(snackbar, 7);
snackbar.show(); snackbar.show();
} else if (ex instanceof IllegalArgumentException) {
Log.i(ex);
Helper.setSnackbarOptions(
Snackbar.make(view, ex.getMessage(), Snackbar.LENGTH_LONG))
.show();
} else } else
Log.unexpectedError(getParentFragmentManager(), ex); Log.unexpectedError(getParentFragmentManager(), ex);
} }

@ -351,7 +351,7 @@ public class FragmentOptionsEncryption extends FragmentBase
btnImportPgp.setOnClickListener(new View.OnClickListener() { btnImportPgp.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
String provider = prefs.getString("openpgp_provider", Helper.PGP_OPENKEYCHAIN_PACKAGE); String provider = PgpHelper.getPackageName(v.getContext());
PackageManager pm = v.getContext().getPackageManager(); PackageManager pm = v.getContext().getPackageManager();
Intent intent = pm.getLaunchIntentForPackage(provider); Intent intent = pm.getLaunchIntentForPackage(provider);
@ -689,7 +689,7 @@ public class FragmentOptionsEncryption extends FragmentBase
swAutoDecrypt.setChecked(prefs.getBoolean("auto_decrypt", false)); swAutoDecrypt.setChecked(prefs.getBoolean("auto_decrypt", false));
swAutoUndoDecrypt.setChecked(prefs.getBoolean("auto_undecrypt", false)); swAutoUndoDecrypt.setChecked(prefs.getBoolean("auto_undecrypt", false));
String provider = prefs.getString("openpgp_provider", Helper.PGP_OPENKEYCHAIN_PACKAGE); String provider = PgpHelper.getPackageName(getContext());
spOpenPgp.setTag(provider); spOpenPgp.setTag(provider);
for (int pos = 0; pos < openPgpProvider.size(); pos++) for (int pos = 0; pos < openPgpProvider.size(); pos++)
if (provider.equals(openPgpProvider.get(pos))) { if (provider.equals(openPgpProvider.get(pos))) {

@ -220,10 +220,6 @@ public class Helper {
static final String PLAY_PACKAGE_NAME = "com.android.vending"; static final String PLAY_PACKAGE_NAME = "com.android.vending";
static final String PGP_OPENKEYCHAIN_PACKAGE = "org.sufficientlysecure.keychain";
static final String PGP_BEGIN_MESSAGE = "-----BEGIN PGP MESSAGE-----";
static final String PGP_END_MESSAGE = "-----END PGP MESSAGE-----";
static final String PACKAGE_WEBVIEW = "https://play.google.com/store/apps/details?id=com.google.android.webview"; static final String PACKAGE_WEBVIEW = "https://play.google.com/store/apps/details?id=com.google.android.webview";
static final String PRIVACY_URI = "https://email.faircode.eu/privacy/"; static final String PRIVACY_URI = "https://email.faircode.eu/privacy/";
static final String TUTORIALS_URI = "https://github.com/M66B/FairEmail/tree/master/tutorials#main"; static final String TUTORIALS_URI = "https://github.com/M66B/FairEmail/tree/master/tutorials#main";

@ -50,6 +50,11 @@ public class PgpHelper {
private static final long CONNECT_TIMEOUT = 5000L; private static final long CONNECT_TIMEOUT = 5000L;
private static final long KEY_TIMEOUT = 250L; private static final long KEY_TIMEOUT = 250L;
static final String PGP_BEGIN_MESSAGE = "-----BEGIN PGP MESSAGE-----";
static final String PGP_END_MESSAGE = "-----END PGP MESSAGE-----";
private static final String PGP_OPENKEYCHAIN_PACKAGE = "org.sufficientlysecure.keychain";
private static final String PGP_PGPONY = "com.pgpony.android";
static Intent execute(Context context, Intent data, InputStream is, OutputStream os) { static Intent execute(Context context, Intent data, InputStream is, OutputStream os) {
return execute(context, data, is, os, CONNECT_TIMEOUT); return execute(context, data, is, os, CONNECT_TIMEOUT);
} }
@ -160,19 +165,26 @@ public class PgpHelper {
} }
static String getPackageName(Context context) { static String getPackageName(Context context) {
PackageManager pm = context.getPackageManager();
Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT_2);
List<ResolveInfo> ris = pm.queryIntentServices(intent, 0); // package whitelisted
if (ris != null && ris.size() == 1 && ris.get(0).serviceInfo != null) {
String pkg = ris.get(0).serviceInfo.packageName;
if (pkg != null)
return pkg;
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("openpgp_provider", Helper.PGP_OPENKEYCHAIN_PACKAGE); return prefs.getString("openpgp_provider", PGP_OPENKEYCHAIN_PACKAGE);
} }
static boolean isOpenKeychainInstalled(Context context) { static boolean isOpenKeychainInstalled(Context context) {
String provider = getPackageName(context);
try { try {
String provider = getPackageName(context);
PackageManager pm = context.getPackageManager(); PackageManager pm = context.getPackageManager();
Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT_2); Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT_2);
intent.setPackage(provider); intent.setPackage(provider);
List<ResolveInfo> ris = pm.queryIntentServices(intent, 0); List<ResolveInfo> ris = pm.queryIntentServices(intent, 0);
return (ris != null && ris.size() > 0); return (ris != null && ris.size() > 0);
} catch (Throwable ex) { } catch (Throwable ex) {
Log.e(ex); Log.e(ex);

@ -1951,9 +1951,9 @@
<string name="title_charset_auto">Automatic</string> <string name="title_charset_auto">Automatic</string>
<string name="title_alternative_text">Load plain text</string> <string name="title_alternative_text">Load plain text</string>
<string name="title_alternative_html">Load HTML</string> <string name="title_alternative_html">Load HTML</string>
<string name="title_no_openpgp">OpenKeychain not found</string> <string name="title_no_openpgp">OpenPGP provider not found</string>
<string name="title_no_openpgp_remark">PGP end-to-end encryption needs to be configured first</string> <string name="title_no_openpgp_remark">PGP end-to-end encryption needs to be configured first</string>
<string name="title_user_interaction">Transferring to OpenKeychain</string> <string name="title_user_interaction">Transferring to OpenPGP provider</string>
<string name="title_padlock">Use the padlock to decrypt the message</string> <string name="title_padlock">Use the padlock to decrypt the message</string>
<string name="title_signed_data">Verify the signature to show the message text</string> <string name="title_signed_data">Verify the signature to show the message text</string>
<string name="title_not_encrypted">Message is not signed or encrypted</string> <string name="title_not_encrypted">Message is not signed or encrypted</string>

Loading…
Cancel
Save