|
@@ -10,206 +10,199 @@
|
|
|
* SPDX-FileCopyrightText: 2014 María Asensio Valverde <masensio@solidgear.es>
|
|
|
* SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only)
|
|
|
*/
|
|
|
-package com.owncloud.android.ui.dialog;
|
|
|
-
|
|
|
-import android.app.Activity;
|
|
|
-import android.app.Dialog;
|
|
|
-import android.net.http.SslError;
|
|
|
-import android.os.Bundle;
|
|
|
-import android.view.View;
|
|
|
-import android.view.View.OnClickListener;
|
|
|
-import android.view.Window;
|
|
|
-import android.webkit.SslErrorHandler;
|
|
|
-import android.widget.Button;
|
|
|
-
|
|
|
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
|
-import com.nextcloud.client.di.Injectable;
|
|
|
-import com.owncloud.android.R;
|
|
|
-import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding;
|
|
|
-import com.owncloud.android.lib.common.network.CertificateCombinedException;
|
|
|
-import com.owncloud.android.lib.common.network.NetworkUtils;
|
|
|
-import com.owncloud.android.lib.common.utils.Log_OC;
|
|
|
-import com.owncloud.android.ui.adapter.CertificateCombinedExceptionViewAdapter;
|
|
|
-import com.owncloud.android.ui.adapter.SslCertificateViewAdapter;
|
|
|
-import com.owncloud.android.ui.adapter.SslErrorViewAdapter;
|
|
|
-import com.owncloud.android.ui.adapter.X509CertificateViewAdapter;
|
|
|
-import com.owncloud.android.utils.theme.ViewThemeUtils;
|
|
|
-
|
|
|
-import java.io.IOException;
|
|
|
-import java.security.GeneralSecurityException;
|
|
|
-import java.security.cert.X509Certificate;
|
|
|
-
|
|
|
-import javax.inject.Inject;
|
|
|
-
|
|
|
-import androidx.annotation.NonNull;
|
|
|
-import androidx.fragment.app.DialogFragment;
|
|
|
+package com.owncloud.android.ui.dialog
|
|
|
+
|
|
|
+import android.app.Dialog
|
|
|
+import android.content.Context
|
|
|
+import android.net.http.SslError
|
|
|
+import android.os.Bundle
|
|
|
+import android.view.View
|
|
|
+import android.view.Window
|
|
|
+import android.webkit.SslErrorHandler
|
|
|
+import android.widget.Button
|
|
|
+import androidx.fragment.app.DialogFragment
|
|
|
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
|
+import com.nextcloud.client.di.Injectable
|
|
|
+import com.owncloud.android.R
|
|
|
+import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding
|
|
|
+import com.owncloud.android.lib.common.network.CertificateCombinedException
|
|
|
+import com.owncloud.android.lib.common.network.NetworkUtils
|
|
|
+import com.owncloud.android.lib.common.utils.Log_OC
|
|
|
+import com.owncloud.android.ui.adapter.CertificateCombinedExceptionViewAdapter
|
|
|
+import com.owncloud.android.ui.adapter.SslCertificateViewAdapter
|
|
|
+import com.owncloud.android.ui.adapter.SslErrorViewAdapter
|
|
|
+import com.owncloud.android.ui.adapter.X509CertificateViewAdapter
|
|
|
+import com.owncloud.android.utils.theme.ViewThemeUtils
|
|
|
+import java.io.IOException
|
|
|
+import java.security.GeneralSecurityException
|
|
|
+import java.security.cert.X509Certificate
|
|
|
+import javax.inject.Inject
|
|
|
|
|
|
/**
|
|
|
* Dialog to show information about an untrusted certificate and allow the user to decide trust on it or not.
|
|
|
* Abstract implementation of common functionality for different dialogs that get the information about the error and
|
|
|
* the certificate from different classes.
|
|
|
*/
|
|
|
-public class SslUntrustedCertDialog extends DialogFragment implements Injectable {
|
|
|
+open class SslUntrustedCertDialog : DialogFragment(), Injectable {
|
|
|
+ @JvmField
|
|
|
+ @Inject
|
|
|
+ var viewThemeUtils: ViewThemeUtils? = null
|
|
|
+
|
|
|
+ protected var binding: SslUntrustedCertLayoutBinding? = null
|
|
|
+ protected var mHandler: SslErrorHandler? = null
|
|
|
+ protected var m509Certificate: X509Certificate? = null
|
|
|
+
|
|
|
+ private var mErrorViewAdapter: ErrorViewAdapter? = null
|
|
|
+ private var mCertificateViewAdapter: CertificateViewAdapter? = null
|
|
|
+
|
|
|
+ override fun onAttach(context: Context) {
|
|
|
+ Log_OC.d(TAG, "onAttach")
|
|
|
+ super.onAttach(context)
|
|
|
+ require(activity is OnSslUntrustedCertListener) {
|
|
|
+ "The host activity must implement " + OnSslUntrustedCertListener::class.java.canonicalName
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- private final static String TAG = SslUntrustedCertDialog.class.getSimpleName();
|
|
|
+ override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
+ Log_OC.d(TAG, "onCreate, savedInstanceState is $savedInstanceState")
|
|
|
+ super.onCreate(savedInstanceState)
|
|
|
|
|
|
- @Inject ViewThemeUtils viewThemeUtils;
|
|
|
+ // force to keep the state of the fragment on configuration changes (such as device rotations)
|
|
|
+ retainInstance = true
|
|
|
+ isCancelable = false
|
|
|
+ binding = null
|
|
|
+ }
|
|
|
|
|
|
- protected SslUntrustedCertLayoutBinding binding;
|
|
|
- protected SslErrorHandler mHandler;
|
|
|
- protected X509Certificate m509Certificate;
|
|
|
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
|
+ Log_OC.d(TAG, "onCreateDialog, savedInstanceState is $savedInstanceState")
|
|
|
|
|
|
- private ErrorViewAdapter mErrorViewAdapter;
|
|
|
- private CertificateViewAdapter mCertificateViewAdapter;
|
|
|
+ binding = SslUntrustedCertLayoutBinding.inflate(layoutInflater, null, false)
|
|
|
+ binding?.detailsScroll?.visibility = View.GONE
|
|
|
+ mErrorViewAdapter?.updateErrorView(binding)
|
|
|
|
|
|
- public static SslUntrustedCertDialog newInstanceForEmptySslError(SslError error, SslErrorHandler handler) {
|
|
|
- if (error == null) {
|
|
|
- throw new IllegalArgumentException("Trying to create instance with parameter error == null");
|
|
|
- }
|
|
|
- if (handler == null) {
|
|
|
- throw new IllegalArgumentException("Trying to create instance with parameter handler == null");
|
|
|
- }
|
|
|
- SslUntrustedCertDialog dialog = new SslUntrustedCertDialog();
|
|
|
- dialog.mHandler = handler;
|
|
|
- dialog.mErrorViewAdapter = new SslErrorViewAdapter(error);
|
|
|
- dialog.mCertificateViewAdapter = new SslCertificateViewAdapter(error.getCertificate());
|
|
|
- return dialog;
|
|
|
- }
|
|
|
+ binding?.ok?.setOnClickListener(OnCertificateTrusted())
|
|
|
|
|
|
- public static SslUntrustedCertDialog newInstanceForFullSslError(CertificateCombinedException sslException) {
|
|
|
- if (sslException == null) {
|
|
|
- throw new IllegalArgumentException("Trying to create instance with parameter sslException == null");
|
|
|
- }
|
|
|
- SslUntrustedCertDialog dialog = new SslUntrustedCertDialog();
|
|
|
- dialog.m509Certificate = sslException.getServerCertificate();
|
|
|
- dialog.mErrorViewAdapter = new CertificateCombinedExceptionViewAdapter(sslException);
|
|
|
- dialog.mCertificateViewAdapter = new X509CertificateViewAdapter(sslException.getServerCertificate());
|
|
|
- return dialog;
|
|
|
- }
|
|
|
+ binding?.cancel?.setOnClickListener(OnCertificateNotTrusted())
|
|
|
|
|
|
- public static SslUntrustedCertDialog newInstanceForFullSslError(X509Certificate cert, SslError error, SslErrorHandler handler) {
|
|
|
- if (cert == null) {
|
|
|
- throw new IllegalArgumentException("Trying to create instance with parameter cert == null");
|
|
|
- }
|
|
|
- if (error == null) {
|
|
|
- throw new IllegalArgumentException("Trying to create instance with parameter error == null");
|
|
|
+ binding?.detailsBtn?.setOnClickListener { v: View ->
|
|
|
+ if (binding?.detailsScroll?.visibility == View.VISIBLE) {
|
|
|
+ binding?.detailsScroll?.visibility = View.GONE
|
|
|
+ (v as Button).setText(R.string.ssl_validator_btn_details_see)
|
|
|
+ } else {
|
|
|
+ binding?.detailsScroll?.visibility = View.VISIBLE
|
|
|
+ (v as Button).setText(R.string.ssl_validator_btn_details_hide)
|
|
|
+ mCertificateViewAdapter?.updateCertificateView(binding)
|
|
|
+ }
|
|
|
}
|
|
|
- if (handler == null) {
|
|
|
- throw new IllegalArgumentException("Trying to create instance with parameter handler == null");
|
|
|
+
|
|
|
+ val builder = MaterialAlertDialogBuilder(requireContext())
|
|
|
+ builder.setView(binding?.getRoot())
|
|
|
+
|
|
|
+ viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder)
|
|
|
+
|
|
|
+ return builder.create().apply {
|
|
|
+ requestWindowFeature(Window.FEATURE_NO_TITLE)
|
|
|
}
|
|
|
- SslUntrustedCertDialog dialog = new SslUntrustedCertDialog();
|
|
|
- dialog.m509Certificate = cert;
|
|
|
- dialog.mHandler = handler;
|
|
|
- dialog.mErrorViewAdapter = new SslErrorViewAdapter(error);
|
|
|
- dialog.mCertificateViewAdapter = new X509CertificateViewAdapter(cert);
|
|
|
- return dialog;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public void onAttach(@NonNull Activity activity) {
|
|
|
- Log_OC.d(TAG, "onAttach");
|
|
|
- super.onAttach(activity);
|
|
|
- if (!(activity instanceof OnSslUntrustedCertListener)) {
|
|
|
- throw new IllegalArgumentException("The host activity must implement " + OnSslUntrustedCertListener.class.getCanonicalName());
|
|
|
+ override fun onDestroyView() {
|
|
|
+ Log_OC.d(TAG, "onDestroyView")
|
|
|
+ if (retainInstance) {
|
|
|
+ dialog?.setDismissMessage(null)
|
|
|
}
|
|
|
+ super.onDestroyView()
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public void onCreate(Bundle savedInstanceState) {
|
|
|
- Log_OC.d(TAG, "onCreate, savedInstanceState is " + savedInstanceState);
|
|
|
- super.onCreate(savedInstanceState);
|
|
|
- setRetainInstance(true); // force to keep the state of the fragment on configuration changes (such as device rotations)
|
|
|
- setCancelable(false);
|
|
|
- binding = null;
|
|
|
+ private inner class OnCertificateNotTrusted : View.OnClickListener {
|
|
|
+ override fun onClick(v: View) {
|
|
|
+ dialog?.cancel()
|
|
|
+ mHandler?.cancel()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- @NonNull
|
|
|
- @Override
|
|
|
- public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
|
- Log_OC.d(TAG, "onCreateDialog, savedInstanceState is " + savedInstanceState);
|
|
|
-
|
|
|
- binding = SslUntrustedCertLayoutBinding.inflate(getLayoutInflater(), null, false);
|
|
|
- binding.detailsScroll.setVisibility(View.GONE);
|
|
|
- mErrorViewAdapter.updateErrorView(binding);
|
|
|
-
|
|
|
- binding.ok.setOnClickListener(new OnCertificateTrusted());
|
|
|
-
|
|
|
- binding.cancel.setOnClickListener(new OnCertificateNotTrusted());
|
|
|
+ private inner class OnCertificateTrusted : View.OnClickListener {
|
|
|
+ override fun onClick(v: View) {
|
|
|
+ dismiss()
|
|
|
+ mHandler?.proceed()
|
|
|
|
|
|
- binding.detailsBtn.setOnClickListener(v -> {
|
|
|
- if (binding.detailsScroll.getVisibility() == View.VISIBLE) {
|
|
|
- binding.detailsScroll.setVisibility(View.GONE);
|
|
|
- ((Button) v).setText(R.string.ssl_validator_btn_details_see);
|
|
|
-
|
|
|
- } else {
|
|
|
- binding.detailsScroll.setVisibility(View.VISIBLE);
|
|
|
- ((Button) v).setText(R.string.ssl_validator_btn_details_hide);
|
|
|
- mCertificateViewAdapter.updateCertificateView(binding);
|
|
|
+ if (m509Certificate == null) {
|
|
|
+ Log_OC.d(TAG, "m509Certificate is null onClick dismissed")
|
|
|
+ return
|
|
|
}
|
|
|
- });
|
|
|
|
|
|
+ if (activity == null) {
|
|
|
+ Log_OC.d(TAG, "activity is null onClick dismissed")
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(binding.getRoot().getContext());
|
|
|
- builder.setView(binding.getRoot());
|
|
|
+ try {
|
|
|
+ // TODO make this asynchronously, it can take some time
|
|
|
+ NetworkUtils.addCertToKnownServersStore(m509Certificate, activity)
|
|
|
+ (activity as OnSslUntrustedCertListener?)?.onSavedCertificate()
|
|
|
+ } catch (e: GeneralSecurityException) {
|
|
|
+ (activity as OnSslUntrustedCertListener?)?.onFailedSavingCertificate()
|
|
|
+ Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e)
|
|
|
+ } catch (e: IOException) {
|
|
|
+ (activity as OnSslUntrustedCertListener?)?.onFailedSavingCertificate()
|
|
|
+ Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.getRoot().getContext(), builder);
|
|
|
+ interface OnSslUntrustedCertListener {
|
|
|
+ fun onSavedCertificate()
|
|
|
+ fun onFailedSavingCertificate()
|
|
|
+ }
|
|
|
|
|
|
- final Dialog dialog = builder.create();
|
|
|
- dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
|
- return dialog;
|
|
|
+ interface ErrorViewAdapter {
|
|
|
+ fun updateErrorView(binding: SslUntrustedCertLayoutBinding?)
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public void onDestroyView() {
|
|
|
- Log_OC.d(TAG, "onDestroyView");
|
|
|
- if (getDialog() != null && getRetainInstance()) {
|
|
|
- getDialog().setDismissMessage(null);
|
|
|
- }
|
|
|
- super.onDestroyView();
|
|
|
+ interface CertificateViewAdapter {
|
|
|
+ fun updateCertificateView(binding: SslUntrustedCertLayoutBinding?)
|
|
|
}
|
|
|
|
|
|
- private class OnCertificateNotTrusted implements OnClickListener {
|
|
|
+ companion object {
|
|
|
+ private val TAG: String = SslUntrustedCertDialog::class.java.simpleName
|
|
|
+
|
|
|
+ @JvmStatic
|
|
|
+ fun newInstanceForEmptySslError(error: SslError?, handler: SslErrorHandler?): SslUntrustedCertDialog {
|
|
|
+ requireNotNull(error) { "Trying to create instance with parameter error == null" }
|
|
|
+ requireNotNull(handler) { "Trying to create instance with parameter handler == null" }
|
|
|
|
|
|
- @Override
|
|
|
- public void onClick(View v) {
|
|
|
- getDialog().cancel();
|
|
|
- if (mHandler != null) {
|
|
|
- mHandler.cancel();
|
|
|
+ return SslUntrustedCertDialog().apply {
|
|
|
+ mHandler = handler
|
|
|
+ mErrorViewAdapter = SslErrorViewAdapter(error)
|
|
|
+ mCertificateViewAdapter = SslCertificateViewAdapter(error.certificate)
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- private class OnCertificateTrusted implements OnClickListener {
|
|
|
+ @JvmStatic
|
|
|
+ fun newInstanceForFullSslError(sslException: CertificateCombinedException?): SslUntrustedCertDialog {
|
|
|
+ requireNotNull(sslException) { "Trying to create instance with parameter sslException == null" }
|
|
|
|
|
|
- @Override
|
|
|
- public void onClick(View v) {
|
|
|
- dismiss();
|
|
|
- if (mHandler != null) {
|
|
|
- mHandler.proceed();
|
|
|
- }
|
|
|
- if (m509Certificate != null) {
|
|
|
- Activity activity = getActivity();
|
|
|
- try {
|
|
|
- NetworkUtils.addCertToKnownServersStore(m509Certificate, activity); // TODO make this asynchronously, it can take some time
|
|
|
- ((OnSslUntrustedCertListener)activity).onSavedCertificate();
|
|
|
- } catch (GeneralSecurityException | IOException e) {
|
|
|
- ((OnSslUntrustedCertListener)activity).onFailedSavingCertificate();
|
|
|
- Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e);
|
|
|
- }
|
|
|
+ return SslUntrustedCertDialog().apply {
|
|
|
+ m509Certificate = sslException.serverCertificate
|
|
|
+ mErrorViewAdapter = CertificateCombinedExceptionViewAdapter(sslException)
|
|
|
+ mCertificateViewAdapter = X509CertificateViewAdapter(sslException.serverCertificate)
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- public interface OnSslUntrustedCertListener {
|
|
|
- void onSavedCertificate();
|
|
|
- void onFailedSavingCertificate();
|
|
|
- }
|
|
|
|
|
|
- public interface ErrorViewAdapter {
|
|
|
- void updateErrorView(SslUntrustedCertLayoutBinding binding);
|
|
|
- }
|
|
|
-
|
|
|
- public interface CertificateViewAdapter {
|
|
|
- void updateCertificateView(SslUntrustedCertLayoutBinding binding);
|
|
|
+ fun newInstanceForFullSslError(
|
|
|
+ cert: X509Certificate?,
|
|
|
+ error: SslError?,
|
|
|
+ handler: SslErrorHandler?
|
|
|
+ ): SslUntrustedCertDialog {
|
|
|
+ requireNotNull(cert) { "Trying to create instance with parameter cert == null" }
|
|
|
+ requireNotNull(error) { "Trying to create instance with parameter error == null" }
|
|
|
+ requireNotNull(handler) { "Trying to create instance with parameter handler == null" }
|
|
|
+
|
|
|
+ return SslUntrustedCertDialog().apply {
|
|
|
+ m509Certificate = cert
|
|
|
+ mHandler = handler
|
|
|
+ mErrorViewAdapter = SslErrorViewAdapter(error)
|
|
|
+ mCertificateViewAdapter = X509CertificateViewAdapter(cert)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|