1 /* ownCloud Android client application 
   2  *   Copyright (C) 2012-2014 ownCloud Inc. 
   4  *   This program is free software: you can redistribute it and/or modify 
   5  *   it under the terms of the GNU General Public License version 2, 
   6  *   as published by the Free Software Foundation. 
   8  *   This program is distributed in the hope that it will be useful, 
   9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
  10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  11  *   GNU General Public License for more details. 
  13  *   You should have received a copy of the GNU General Public License 
  14  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  17 package com
.owncloud
.android
.ui
.dialog
; 
  19 import java
.io
.IOException
; 
  20 import java
.security
.GeneralSecurityException
; 
  21 import java
.security
.cert
.X509Certificate
; 
  23 import android
.app
.Activity
; 
  24 import android
.app
.Dialog
; 
  25 import android
.net
.http
.SslError
; 
  26 import android
.os
.Bundle
; 
  27 import android
.view
.LayoutInflater
; 
  28 import android
.view
.View
; 
  29 import android
.view
.ViewGroup
; 
  30 import android
.view
.Window
; 
  31 import android
.view
.View
.OnClickListener
; 
  32 import android
.webkit
.SslErrorHandler
; 
  33 import android
.widget
.Button
; 
  35 import com
.actionbarsherlock
.app
.SherlockDialogFragment
; 
  36 import com
.owncloud
.android
.R
; 
  37 import com
.owncloud
.android
.lib
.common
.network
.CertificateCombinedException
; 
  38 import com
.owncloud
.android
.lib
.common
.network
.NetworkUtils
; 
  39 import com
.owncloud
.android
.ui
.adapter
.CertificateCombinedExceptionViewAdapter
; 
  40 import com
.owncloud
.android
.ui
.adapter
.SslCertificateViewAdapter
; 
  41 import com
.owncloud
.android
.ui
.adapter
.SslErrorViewAdapter
; 
  42 import com
.owncloud
.android
.ui
.adapter
.X509CertificateViewAdapter
; 
  43 import com
.owncloud
.android
.utils
.Log_OC
; 
  46  * Dialog to show information about an untrusted certificate and allow the user 
  47  * to decide trust on it or not. 
  49  * Abstract implementation of common functionality for different dialogs that 
  50  * get the information about the error and the certificate from different classes.  
  53  * @author David A. Velasco 
  55 public class SslUntrustedCertDialog 
extends SherlockDialogFragment 
{ 
  57     private final static String TAG 
= SslUntrustedCertDialog
.class.getSimpleName(); 
  59     protected View mView 
= null
; 
  60     protected SslErrorHandler mHandler 
= null
; 
  61     protected X509Certificate m509Certificate 
= null
; 
  63     private ErrorViewAdapter mErrorViewAdapter 
= null
; 
  64     private CertificateViewAdapter mCertificateViewAdapter 
= null
; 
  66     public static SslUntrustedCertDialog 
newInstanceForEmptySslError(SslError error
, SslErrorHandler handler
) { 
  68             throw new IllegalArgumentException("Trying to create instance with parameter error == null"); 
  70         if (handler 
== null
) { 
  71             throw new IllegalArgumentException("Trying to create instance with parameter handler == null"); 
  73         SslUntrustedCertDialog dialog 
= new SslUntrustedCertDialog(); 
  74         dialog
.mHandler 
= handler
; 
  75         dialog
.mErrorViewAdapter 
= new SslErrorViewAdapter(error
); 
  76         dialog
.mCertificateViewAdapter 
= new SslCertificateViewAdapter(error
.getCertificate()); 
  80     public static SslUntrustedCertDialog 
newInstanceForFullSslError(CertificateCombinedException sslException
) { 
  81         if (sslException 
== null
) { 
  82             throw new IllegalArgumentException("Trying to create instance with parameter sslException == null"); 
  84         SslUntrustedCertDialog dialog 
= new SslUntrustedCertDialog(); 
  85         dialog
.m509Certificate 
= sslException
.getServerCertificate(); 
  86         dialog
.mErrorViewAdapter 
= new CertificateCombinedExceptionViewAdapter(sslException
); 
  87         dialog
.mCertificateViewAdapter 
= new X509CertificateViewAdapter(sslException
.getServerCertificate()); 
  91     public static SslUntrustedCertDialog 
newInstanceForFullSslError(X509Certificate cert
, SslError error
, SslErrorHandler handler
) { 
  93             throw new IllegalArgumentException("Trying to create instance with parameter cert == null"); 
  96             throw new IllegalArgumentException("Trying to create instance with parameter error == null"); 
  98         if (handler 
== null
) { 
  99             throw new IllegalArgumentException("Trying to create instance with parameter handler == null"); 
 101         SslUntrustedCertDialog dialog 
= new SslUntrustedCertDialog(); 
 102         dialog
.m509Certificate 
= cert
; 
 103         dialog
.mHandler 
= handler
; 
 104         dialog
.mErrorViewAdapter 
= new SslErrorViewAdapter(error
); 
 105         dialog
.mCertificateViewAdapter 
= new X509CertificateViewAdapter(cert
); 
 111     public void onAttach(Activity activity
) { 
 112         Log_OC
.d(TAG
, "onAttach"); 
 113         super.onAttach(activity
); 
 114         if (!(activity 
instanceof OnSslUntrustedCertListener
)) { 
 115             throw new IllegalArgumentException("The host activity must implement " + OnSslUntrustedCertListener
.class.getCanonicalName()); 
 121     public void onCreate(Bundle savedInstanceState
) { 
 122         Log_OC
.d(TAG
, "onCreate, savedInstanceState is " + savedInstanceState
); 
 123         super.onCreate(savedInstanceState
); 
 124         setRetainInstance(true
);    // force to keep the state of the fragment on configuration changes (such as device rotations) 
 125         setCancelable(false
); 
 130     public View 
onCreateView(LayoutInflater inflater
, ViewGroup container
, Bundle savedInstanceState
) { 
 131         Log_OC
.d(TAG
, "onCreateView, savedInsanceState is " + savedInstanceState
); 
 132         // Create a view by inflating desired layout 
 134             mView 
= inflater
.inflate(R
.layout
.ssl_untrusted_cert_layout
, container
,  false
); 
 135             mView
.findViewById(R
.id
.details_scroll
).setVisibility(View
.GONE
); 
 136             mErrorViewAdapter
.updateErrorView(mView
); 
 138             ((ViewGroup
)mView
.getParent()).removeView(mView
); 
 141         Button ok 
= (Button
) mView
.findViewById(R
.id
.ok
); 
 142         ok
.setOnClickListener(new OnCertificateTrusted()); 
 144         Button cancel 
= (Button
) mView
.findViewById(R
.id
.cancel
); 
 145         cancel
.setOnClickListener(new OnCertificateNotTrusted()); 
 147         Button details 
= (Button
) mView
.findViewById(R
.id
.details_btn
); 
 148         details
.setOnClickListener(new OnClickListener() { 
 151             public void onClick(View v
) { 
 152                 View detailsScroll 
= mView
.findViewById(R
.id
.details_scroll
); 
 153                 if (detailsScroll
.getVisibility() == View
.VISIBLE
) { 
 154                     detailsScroll
.setVisibility(View
.GONE
); 
 155                     ((Button
) v
).setText(R
.string
.ssl_validator_btn_details_see
); 
 158                     detailsScroll
.setVisibility(View
.VISIBLE
); 
 159                     ((Button
) v
).setText(R
.string
.ssl_validator_btn_details_hide
); 
 160                     mCertificateViewAdapter
.updateCertificateView(mView
); 
 171     public Dialog 
onCreateDialog(Bundle savedInstanceState
) { 
 172         Log_OC
.d(TAG
, "onCreateDialog, savedInstanceState is " + savedInstanceState
); 
 173         final Dialog dialog 
= super.onCreateDialog(savedInstanceState
); 
 174         dialog
.requestWindowFeature(Window
.FEATURE_NO_TITLE
); 
 179     public void onDestroyView() { 
 180         Log_OC
.d(TAG
, "onDestroyView"); 
 181         if (getDialog() != null 
&& getRetainInstance()) 
 182             getDialog().setDismissMessage(null
); 
 183         super.onDestroyView(); 
 186     private class OnCertificateNotTrusted 
implements OnClickListener 
{ 
 189         public void onClick(View v
) { 
 190             getDialog().cancel(); 
 191             if (mHandler 
!= null
) { 
 194             ((OnSslUntrustedCertListener
)getSherlockActivity()).onCancelCertificate(); 
 199     private class OnCertificateTrusted 
implements OnClickListener 
{ 
 202         public void onClick(View v
) { 
 204             if (mHandler 
!= null
) { 
 207             if (m509Certificate 
!= null
) { 
 208                 Activity activity 
= getSherlockActivity(); 
 210                     NetworkUtils
.addCertToKnownServersStore(m509Certificate
, activity
);   // TODO make this asynchronously, it can take some time 
 211                     ((OnSslUntrustedCertListener
)activity
).onSavedCertificate(); 
 213                 } catch (GeneralSecurityException e
) { 
 214                     ((OnSslUntrustedCertListener
)activity
).onFailedSavingCertificate(); 
 215                     Log_OC
.e(TAG
, "Server certificate could not be saved in the known-servers trust store ", e
); 
 217                 } catch (IOException e
) { 
 218                     ((OnSslUntrustedCertListener
)activity
).onFailedSavingCertificate(); 
 219                     Log_OC
.e(TAG
, "Server certificate could not be saved in the known-servers trust store ", e
); 
 227     public interface OnSslUntrustedCertListener 
{ 
 228         public void onSavedCertificate(); 
 229         public void onFailedSavingCertificate(); 
 230         public void onCancelCertificate(); 
 233     public interface ErrorViewAdapter 
{ 
 234         void updateErrorView(View mView
); 
 237     public interface CertificateViewAdapter 
{ 
 238         void updateCertificateView(View mView
);