Fix buttons out of screen in SSL warning dialogs for small screens in landspace
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / dialog / SslUntrustedCertDialog.java
1 /* ownCloud Android client application
2 * Copyright (C) 2012-2014 ownCloud Inc.
3 *
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.
7 *
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.
12 *
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/>.
15 *
16 */
17 package com.owncloud.android.ui.dialog;
18
19 import java.io.IOException;
20 import java.security.GeneralSecurityException;
21 import java.security.KeyStoreException;
22 import java.security.NoSuchAlgorithmException;
23 import java.security.cert.CertificateException;
24 import java.security.cert.X509Certificate;
25 import java.util.Date;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import javax.security.auth.x500.X500Principal;
30
31 import com.owncloud.android.R;
32 import com.owncloud.android.authentication.AuthenticatorActivity;
33 import com.owncloud.android.lib.common.network.NetworkUtils;
34 import com.owncloud.android.utils.Log_OC;
35
36 import android.app.Activity;
37 import android.app.Dialog;
38 import android.content.Context;
39 import android.os.Bundle;
40 import android.view.LayoutInflater;
41 import android.view.View;
42 import android.view.View.OnClickListener;
43 import android.view.ViewGroup;
44 import android.view.Window;
45 import android.webkit.SslErrorHandler;
46 import android.widget.Button;
47 import android.widget.TextView;
48
49 /**
50 * Dialog to show an Untrusted Certificate
51 *
52 * @author masensio
53 *
54 */
55 public class SslUntrustedCertDialog extends SslUntrustedCertDialogABSTRACT {
56
57 private final static String TAG = SslUntrustedCertDialog.class.getSimpleName();
58
59 private X509Certificate mCertificate;
60 private View mView;
61 private SslErrorHandler mHandler;
62
63 private OnSslUntrustedCertListener mListener;
64
65 public SslUntrustedCertDialog() {
66 }
67
68 public SslUntrustedCertDialog(X509Certificate cert, OnSslUntrustedCertListener listener, SslErrorHandler handler) {
69 mCertificate = cert;
70 mListener = listener;
71 mHandler = handler;
72 }
73
74 public static SslUntrustedCertDialog newInstance(Context context, X509Certificate cert, OnSslUntrustedCertListener listener,
75 SslErrorHandler handler) {
76 if (cert != null){
77 SslUntrustedCertDialog dialog = new SslUntrustedCertDialog(cert, listener, handler);
78 return dialog;
79 } else {
80 return null;
81 }
82 }
83
84 @Override
85 public void onCreate(Bundle savedInstanceState) {
86 super.onCreate(savedInstanceState);
87 setRetainInstance(true);
88 setCancelable(true);
89 }
90
91 @Override
92 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
93 // Create a view by inflating desired layout
94 mView = inflater.inflate(R.layout.ssl_untrusted_cert_layout, container, false);
95
96 Button ok = (Button) mView.findViewById(R.id.untrusted_ok);
97 ok.setOnClickListener(new OnClickListener() {
98
99 @Override
100 public void onClick(View v) {
101 try {
102 saveServerCert();
103 dismiss();
104 if (mListener != null) {
105 ((AuthenticatorActivity)getSherlockActivity()).reloadWebView();
106
107 }
108 else
109 Log_OC.d(TAG, "Nobody there to notify the certificate was saved");
110
111 } catch (GeneralSecurityException e) {
112 dismiss();
113 if (mListener != null) {
114 ((AuthenticatorActivity)getSherlockActivity()).cancelWebView();
115 mListener.onFailedSavingCertificate();
116 }
117 Log_OC.e(TAG, "Server certificate could not be saved in the known servers trust store ", e);
118
119 } catch (IOException e) {
120 dismiss();
121 if (mListener != null) {
122 ((AuthenticatorActivity)getSherlockActivity()).cancelWebView();
123 mListener.onFailedSavingCertificate();
124 }
125 Log_OC.e(TAG, "Server certificate could not be saved in the known servers trust store ", e);
126 }
127
128 }
129 });
130
131 Button cancel = (Button) mView.findViewById(R.id.untrusted_cancel);
132 cancel.setOnClickListener(new OnClickListener() {
133
134 @Override
135 public void onClick(View v) {
136 getDialog().cancel();
137 ((AuthenticatorActivity)getSherlockActivity()).cancelWebView();
138 }
139 });
140
141 Button details = (Button) mView.findViewById(R.id.untrusted_details_btn);
142 details.setOnClickListener(new OnClickListener() {
143
144 @Override
145 public void onClick(View v) {
146 View detailsScroll = mView.findViewById(R.id.untrusted_details_scroll);
147 if (detailsScroll.getVisibility() == View.VISIBLE) {
148 detailsScroll.setVisibility(View.GONE);
149 ((Button) v).setText(R.string.ssl_validator_btn_details_see);
150
151 } else {
152 detailsScroll.setVisibility(View.VISIBLE);
153 ((Button) v).setText(R.string.ssl_validator_btn_details_hide);
154
155 showCertificateData(mCertificate);
156 }
157
158 }
159 });
160
161 return mView;
162 }
163
164 @Override
165 public Dialog onCreateDialog(Bundle savedInstanceState) {
166 final Dialog dialog = super.onCreateDialog(savedInstanceState);
167 dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
168
169 return dialog;
170 }
171
172 @Override
173 public void onDestroyView() {
174 if (getDialog() != null && getRetainInstance())
175 getDialog().setDismissMessage(null);
176 super.onDestroyView();
177 }
178
179 private void showCertificateData(X509Certificate cert) {
180
181 TextView nullCerView = (TextView) mView.findViewById(R.id.untrusted_null_cert);
182
183 if (cert != null) {
184 nullCerView.setVisibility(View.GONE);
185 showSubject(cert.getSubjectX500Principal());
186 showIssuer(cert.getIssuerX500Principal());
187 showValidity(cert.getNotBefore(), cert.getNotAfter());
188 showSignature(cert);
189
190 } else {
191 nullCerView.setVisibility(View.VISIBLE);
192 }
193 }
194
195 private void showSignature(X509Certificate cert) {
196 TextView sigView = ((TextView)mView.findViewById(R.id.untrusted_value_signature));
197 TextView algorithmView = ((TextView)mView.findViewById(R.id.untrusted_value_signature_algorithm));
198 sigView.setText(getHex(cert.getSignature()));
199 algorithmView.setText(cert.getSigAlgName());
200 }
201
202 public String getHex(final byte [] raw) {
203 if (raw == null) {
204 return null;
205 }
206 final StringBuilder hex = new StringBuilder(2 * raw.length);
207 for (final byte b : raw) {
208 final int hiVal = (b & 0xF0) >> 4;
209 final int loVal = b & 0x0F;
210 hex.append((char) ('0' + (hiVal + (hiVal / 10 * 7))));
211 hex.append((char) ('0' + (loVal + (loVal / 10 * 7))));
212 }
213 return hex.toString();
214 }
215
216 @SuppressWarnings("deprecation")
217 private void showValidity(Date notBefore, Date notAfter) {
218 TextView fromView = ((TextView)mView.findViewById(R.id.untrusted_value_validity_from));
219 TextView toView = ((TextView)mView.findViewById(R.id.untrusted_value_validity_to));
220 fromView.setText(notBefore.toLocaleString());
221 toView.setText(notAfter.toLocaleString());
222 }
223
224 private void showSubject(X500Principal subject) {
225 Map<String, String> s = parsePrincipal(subject);
226 TextView cnView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_CN));
227 TextView oView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_O));
228 TextView ouView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_OU));
229 TextView cView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_C));
230 TextView stView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_ST));
231 TextView lView = ((TextView)mView.findViewById(R.id.untrusted_value_subject_L));
232
233 if (s.get("CN") != null) {
234 cnView.setText(s.get("CN"));
235 cnView.setVisibility(View.VISIBLE);
236 } else {
237 cnView.setVisibility(View.GONE);
238 }
239 if (s.get("O") != null) {
240 oView.setText(s.get("O"));
241 oView.setVisibility(View.VISIBLE);
242 } else {
243 oView.setVisibility(View.GONE);
244 }
245 if (s.get("OU") != null) {
246 ouView.setText(s.get("OU"));
247 ouView.setVisibility(View.VISIBLE);
248 } else {
249 ouView.setVisibility(View.GONE);
250 }
251 if (s.get("C") != null) {
252 cView.setText(s.get("C"));
253 cView.setVisibility(View.VISIBLE);
254 } else {
255 cView.setVisibility(View.GONE);
256 }
257 if (s.get("ST") != null) {
258 stView.setText(s.get("ST"));
259 stView.setVisibility(View.VISIBLE);
260 } else {
261 stView.setVisibility(View.GONE);
262 }
263 if (s.get("L") != null) {
264 lView.setText(s.get("L"));
265 lView.setVisibility(View.VISIBLE);
266 } else {
267 lView.setVisibility(View.GONE);
268 }
269 }
270
271 private void showIssuer(X500Principal issuer) {
272 Map<String, String> s = parsePrincipal(issuer);
273 TextView cnView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_CN));
274 TextView oView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_O));
275 TextView ouView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_OU));
276 TextView cView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_C));
277 TextView stView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_ST));
278 TextView lView = ((TextView)mView.findViewById(R.id.untrusted_value_issuer_L));
279
280 if (s.get("CN") != null) {
281 cnView.setText(s.get("CN"));
282 cnView.setVisibility(View.VISIBLE);
283 } else {
284 cnView.setVisibility(View.GONE);
285 }
286 if (s.get("O") != null) {
287 oView.setText(s.get("O"));
288 oView.setVisibility(View.VISIBLE);
289 } else {
290 oView.setVisibility(View.GONE);
291 }
292 if (s.get("OU") != null) {
293 ouView.setText(s.get("OU"));
294 ouView.setVisibility(View.VISIBLE);
295 } else {
296 ouView.setVisibility(View.GONE);
297 }
298 if (s.get("C") != null) {
299 cView.setText(s.get("C"));
300 cView.setVisibility(View.VISIBLE);
301 } else {
302 cView.setVisibility(View.GONE);
303 }
304 if (s.get("ST") != null) {
305 stView.setText(s.get("ST"));
306 stView.setVisibility(View.VISIBLE);
307 } else {
308 stView.setVisibility(View.GONE);
309 }
310 if (s.get("L") != null) {
311 lView.setText(s.get("L"));
312 lView.setVisibility(View.VISIBLE);
313 } else {
314 lView.setVisibility(View.GONE);
315 }
316 }
317
318
319 private Map<String, String> parsePrincipal(X500Principal principal) {
320 Map<String, String> result = new HashMap<String, String>();
321 String toParse = principal.getName();
322 String[] pieces = toParse.split(",");
323 String[] tokens = {"CN", "O", "OU", "C", "ST", "L"};
324 for (int i=0; i < pieces.length ; i++) {
325 for (int j=0; j<tokens.length; j++) {
326 if (pieces[i].startsWith(tokens[j] + "=")) {
327 result.put(tokens[j], pieces[i].substring(tokens[j].length()+1));
328 }
329 }
330 }
331 return result;
332 }
333
334 private void saveServerCert() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
335 if (mCertificate != null) {
336 // TODO make this asynchronously, it can take some time
337 NetworkUtils.addCertToKnownServersStore(mCertificate, getSherlockActivity());
338 }
339 }
340
341 public interface OnSslUntrustedCertListener {
342 public void onFailedSavingCertificate();
343 }
344
345 }