diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteSecurityProblemDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteSecurityProblemDialogActivity.java index b03c693b5..2426e572e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteSecurityProblemDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteSecurityProblemDialogActivity.java @@ -18,10 +18,228 @@ package org.sufficientlysecure.keychain.remote.ui; +import java.io.Serializable; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.remote.ui.SecurityProblemPresenter.RemoteSecurityProblemView; +import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.ui.util.ThemeChanger; public class RemoteSecurityProblemDialogActivity extends FragmentActivity { public static final String EXTRA_PACKAGE_NAME = "package_name"; public static final String EXTRA_SECURITY_PROBLEM = "security_problem"; + + + private SecurityProblemPresenter presenter; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + this.presenter = new SecurityProblemPresenter(getBaseContext()); + + if (savedInstanceState == null) { + RemoteRegisterDialogFragment frag = new RemoteRegisterDialogFragment(); + frag.show(getSupportFragmentManager(), "requestKeyDialog"); + } + } + + @Override + protected void onStart() { + super.onStart(); + + Intent intent = getIntent(); + String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); + Serializable keySecurityProblem = intent.getSerializableExtra(EXTRA_SECURITY_PROBLEM); + + presenter.setupFromIntentData(packageName, keySecurityProblem); + } + + public static class RemoteRegisterDialogFragment extends DialogFragment { + private SecurityProblemPresenter presenter; + private RemoteSecurityProblemView mvpView; + + private Button buttonGotIt; + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Activity activity = getActivity(); + + ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity); + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme); + + @SuppressLint("InflateParams") + View view = LayoutInflater.from(theme).inflate(R.layout.remote_security_issue_dialog, null, false); + alert.setView(view); + + buttonGotIt = (Button) view.findViewById(R.id.button_allow); + + setupListenersForPresenter(); + mvpView = createMvpView(view); + + return alert.create(); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + presenter = ((RemoteSecurityProblemDialogActivity) getActivity()).presenter; + presenter.setView(mvpView); + } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + + if (presenter != null) { + presenter.onCancel(); + } + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + + if (presenter != null) { + presenter.setView(null); + presenter = null; + } + } + + @NonNull + private RemoteSecurityProblemView createMvpView(View view) { + final LinearLayout insecureWarningLayout = (LinearLayout) view.findViewById(R.id.insecure_warning_layout); + final ImageView iconClientApp = (ImageView) view.findViewById(R.id.icon_client_app); + final TextView explanationText = (TextView) insecureWarningLayout.findViewById(R.id.dialog_insecure_text); + final TextView recommendText = (TextView) insecureWarningLayout.findViewById(R.id.dialog_insecure_recommend_text); + final View recommendLayout = insecureWarningLayout.findViewById(R.id.dialog_insecure_recommend_layout); + + return new RemoteSecurityProblemView() { + @Override + public void finishAsCancelled() { + FragmentActivity activity = getActivity(); + if (activity == null) { + return; + } + + activity.setResult(RESULT_CANCELED); + activity.finish(); + } + + @Override + public void setTitleClientIcon(Drawable drawable) { + iconClientApp.setImageDrawable(drawable); + } + + /* specialized layouts, for later? + private void inflateWarningContentLayout(int dialog_insecure_mdc) { + insecureWarningLayout.removeAllViews(); + getLayoutInflater(null).inflate(dialog_insecure_mdc, insecureWarningLayout); + } + */ + + private void showGeneric(@StringRes int explanationStringRes) { + explanationText.setText(explanationStringRes); + recommendLayout.setVisibility(View.GONE); + } + + private void showGenericWithRecommendation( + @StringRes int explanationStringRes, @StringRes int recommendationStringRes) { + explanationText.setText(explanationStringRes); + recommendText.setText(recommendationStringRes); + recommendLayout.setVisibility(View.VISIBLE); + } + + @Override + public void showLayoutMissingMdc() { + showGenericWithRecommendation(R.string.insecure_msg_mdc, R.string.insecure_recom_mdc); + } + + @Override + public void showLayoutInsecureSymmetric(int symmetricAlgorithm) { + showGeneric(R.string.insecure_msg_unidentified_key); + } + + @Override + public void showLayoutInsecureHashAlgorithm(int hashAlgorithm) { + showGeneric(R.string.insecure_msg_unidentified_key); + } + + @Override + public void showLayoutEncryptInsecureBitsize(int algorithmId, int bitStrength) { + String algorithmName = KeyFormattingUtils.getAlgorithmInfo(algorithmId, null, null); + explanationText.setText( + getString(R.string.insecure_msg_bitstrength, algorithmName, + Integer.toString(bitStrength), "2010")); + recommendText.setText(R.string.insecure_recom_new_key); + recommendText.setVisibility(View.VISIBLE); + } + + @Override + public void showLayoutSignInsecureBitsize(int algorithmId, int bitStrength) { + String algorithmName = KeyFormattingUtils.getAlgorithmInfo(algorithmId, null, null); + explanationText.setText( + getString(R.string.insecure_msg_bitstrength, algorithmName, + Integer.toString(bitStrength), "2010")); + recommendText.setText(R.string.insecure_recom_new_key); + recommendText.setVisibility(View.VISIBLE); + } + + @Override + public void showLayoutEncryptNotWhitelistedCurve(String curveOid) { + showGeneric(R.string.insecure_msg_not_whitelisted_curve); + } + + @Override + public void showLayoutSignNotWhitelistedCurve(String curveOid) { + showGeneric(R.string.insecure_msg_not_whitelisted_curve); + } + + @Override + public void showLayoutEncryptUnidentifiedKeyProblem() { + showGeneric(R.string.insecure_msg_unidentified_key); + } + + @Override + public void showLayoutSignUnidentifiedKeyProblem() { + showGeneric(R.string.insecure_msg_unidentified_key); + } + }; + } + + private void setupListenersForPresenter() { + buttonGotIt.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + presenter.onClickGotIt(); + } + }); + } + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/SecurityProblemPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/SecurityProblemPresenter.java new file mode 100644 index 000000000..bbc5786a5 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/SecurityProblemPresenter.java @@ -0,0 +1,140 @@ +package org.sufficientlysecure.keychain.remote.ui; + + +import java.io.Serializable; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.drawable.Drawable; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureBitStrength; +import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureHashAlgorithm; +import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureSymmetricAlgorithm; +import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem; +import org.sufficientlysecure.keychain.pgp.SecurityProblem.MissingMdc; +import org.sufficientlysecure.keychain.pgp.SecurityProblem.NotWhitelistedCurve; +import org.sufficientlysecure.keychain.pgp.SecurityProblem.SymmetricAlgorithmProblem; +import org.sufficientlysecure.keychain.pgp.SecurityProblem.UnidentifiedKeyProblem; +import org.sufficientlysecure.keychain.pgp.SecurityProblem.UsageType; +import org.sufficientlysecure.keychain.util.Log; + + +class SecurityProblemPresenter { + private final PackageManager packageManager; + + + private RemoteSecurityProblemView view; + + + SecurityProblemPresenter(Context context) { + packageManager = context.getPackageManager(); + } + + public void setView(RemoteSecurityProblemView view) { + this.view = view; + } + + void setupFromIntentData(String packageName, Serializable securityProblem) { + + if (securityProblem instanceof KeySecurityProblem) { +// setupFromKeySecurityProblem((KeySecurityProblem) securityProblem); + } else if (securityProblem instanceof SymmetricAlgorithmProblem) { + setupFromNonKeySecurityProblem((SymmetricAlgorithmProblem) securityProblem); + } else if (securityProblem instanceof InsecureHashAlgorithm) { + setupFromInsecureHashAlgorithm((InsecureHashAlgorithm) securityProblem); + } else { + throw new IllegalArgumentException("Unhandled security problem type!"); + } + + try { + setPackageInfo(packageName); + } catch (NameNotFoundException e) { + throw new IllegalStateException("Unable to find info of calling app!", e); + } + } + + /* + private void setupFromKeySecurityProblem(KeySecurityProblem keySecurityProblem) { + if (keySecurityProblem instanceof InsecureBitStrength) { + InsecureBitStrength problem = (InsecureBitStrength) keySecurityProblem; + if (problem.usageType == UsageType.ENCRYPT) { + view.showLayoutEncryptInsecureBitsize(problem.algorithm, problem.bitStrength); + } else if (problem.usageType == UsageType.SIGN) { + view.showLayoutSignInsecureBitsize(problem.algorithm, problem.bitStrength); + } else { + throw new IllegalStateException("Should never happen here!"); + } + } else if (keySecurityProblem instanceof NotWhitelistedCurve) { + NotWhitelistedCurve problem = (NotWhitelistedCurve) keySecurityProblem; + if (problem.usageType == UsageType.ENCRYPT) { + view.showLayoutEncryptNotWhitelistedCurve(problem.curveOid); + } else if (problem.usageType == UsageType.SIGN) { + view.showLayoutSignNotWhitelistedCurve(problem.curveOid); + } else { + throw new IllegalStateException("Should never happen here!"); + } + } else if (keySecurityProblem instanceof UnidentifiedKeyProblem) { + if (keySecurityProblem.usageType == UsageType.ENCRYPT) { + view.showLayoutEncryptUnidentifiedKeyProblem(); + } else if (keySecurityProblem.usageType == UsageType.SIGN) { + view.showLayoutSignUnidentifiedKeyProblem(); + } else { + throw new IllegalStateException("Should never happen here!"); + } + } else { + throw new IllegalArgumentException("Unhandled key security problem type!"); + } + } + */ + + private void setupFromNonKeySecurityProblem(SymmetricAlgorithmProblem securityProblem) { + if (securityProblem instanceof MissingMdc) { + view.showLayoutMissingMdc(); + } else if (securityProblem instanceof InsecureSymmetricAlgorithm) { + InsecureSymmetricAlgorithm insecureSymmetricAlgorithm = (InsecureSymmetricAlgorithm) securityProblem; + view.showLayoutInsecureSymmetric(insecureSymmetricAlgorithm.symmetricAlgorithm); + } else { + throw new IllegalArgumentException("Unhandled symmetric algorithm problem type!"); + } + } + + private void setupFromInsecureHashAlgorithm(InsecureHashAlgorithm securityProblem) { + view.showLayoutInsecureHashAlgorithm(securityProblem.hashAlgorithm); + } + + private void setPackageInfo(String packageName) throws NameNotFoundException { + ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0); + Drawable appIcon = packageManager.getApplicationIcon(applicationInfo); + // CharSequence appName = packageManager.getApplicationLabel(applicationInfo); + + view.setTitleClientIcon(appIcon); + } + + void onClickGotIt() { + view.finishAsCancelled(); + } + + void onCancel() { + view.finishAsCancelled(); + } + + interface RemoteSecurityProblemView { + void finishAsCancelled(); + void setTitleClientIcon(Drawable drawable); + + void showLayoutEncryptInsecureBitsize(int algorithmId, int bitStrength); + void showLayoutEncryptNotWhitelistedCurve(String curveOid); + void showLayoutEncryptUnidentifiedKeyProblem(); + void showLayoutSignInsecureBitsize(int algorithmId, int bitStrength); + void showLayoutSignNotWhitelistedCurve(String curveOid); + void showLayoutSignUnidentifiedKeyProblem(); + + void showLayoutMissingMdc(); + void showLayoutInsecureSymmetric(int symmetricAlgorithm); + + void showLayoutInsecureHashAlgorithm(int hashAlgorithm); + } +} diff --git a/OpenKeychain/src/main/res/layout/dialog_insecure_bitsize.xml b/OpenKeychain/src/main/res/layout/dialog_insecure_bitsize.xml new file mode 100644 index 000000000..e913e04ab --- /dev/null +++ b/OpenKeychain/src/main/res/layout/dialog_insecure_bitsize.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + diff --git a/OpenKeychain/src/main/res/layout/dialog_insecure_generic.xml b/OpenKeychain/src/main/res/layout/dialog_insecure_generic.xml new file mode 100644 index 000000000..a9d9400f4 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/dialog_insecure_generic.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + diff --git a/OpenKeychain/src/main/res/layout/remote_security_issue_dialog.xml b/OpenKeychain/src/main/res/layout/remote_security_issue_dialog.xml new file mode 100644 index 000000000..1eeef98c8 --- /dev/null +++ b/OpenKeychain/src/main/res/layout/remote_security_issue_dialog.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +