Index: chrome/android/java/src/org/chromium/chrome/browser/CertificateViewer.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/CertificateViewer.java b/chrome/android/java/src/org/chromium/chrome/browser/CertificateViewer.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bfcf3e2b2d94b0b465fae2f6be37f5a2dcc2292e |
--- /dev/null |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/CertificateViewer.java |
@@ -0,0 +1,201 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.chrome.browser; |
+ |
+import android.app.Dialog; |
+import android.content.Context; |
+import android.graphics.Typeface; |
+import android.net.http.SslCertificate; |
+import android.text.format.DateFormat; |
+import android.util.Log; |
+import android.view.View; |
+import android.widget.AdapterView; |
+import android.widget.AdapterView.OnItemSelectedListener; |
+import android.widget.ArrayAdapter; |
+import android.widget.LinearLayout; |
+import android.widget.ScrollView; |
+import android.widget.Spinner; |
+import android.widget.TextView; |
+ |
+import org.chromium.chrome.R; |
+ |
+import java.io.ByteArrayInputStream; |
+import java.security.cert.Certificate; |
+import java.security.cert.CertificateException; |
+import java.security.cert.CertificateFactory; |
+import java.security.cert.X509Certificate; |
+import java.util.ArrayList; |
+ |
+/** |
+ * UI component for displaying certificate information. |
+ */ |
+public class CertificateViewer implements OnItemSelectedListener { |
+ CertificateFactory mCertificateFactory; |
Ted C
2013/01/25 02:04:05
are these intentionally package scoped? I suspect
Yaron
2013/01/25 19:25:17
Done.
|
+ Context mContext; |
+ ArrayList<LinearLayout> mViews; |
+ ArrayList<String> mTitles; |
+ int mPadding; |
+ |
+ public static void showCert(Context context, byte[] der_data) { |
Ted C
2013/01/25 02:04:05
all public methods should have javadoc.
Yaron
2013/01/25 19:25:17
Done.
|
+ CertificateViewer viewer = new CertificateViewer(context); |
+ viewer.showCertificate(der_data); |
+ } |
+ |
+ public static void showCertChain(Context context, byte[][] der_data) { |
Ted C
2013/01/25 02:04:05
der_data should be camel cased (and all other usag
Yaron
2013/01/25 19:25:17
Done.
|
+ CertificateViewer viewer = new CertificateViewer(context); |
+ viewer.showCertificateChain(der_data); |
+ } |
+ |
+ private CertificateViewer(Context context) { |
+ mContext = context; |
+ mViews = new ArrayList<LinearLayout>(); |
+ mTitles = new ArrayList<String>(); |
+ mPadding = (int) context.getResources().getDimension( |
+ R.dimen.certificate_viewer_padding) / 2; |
Ted C
2013/01/25 02:04:05
why is it dividing by two?
Yaron
2013/01/25 19:25:17
I tried removing and there's too much vertical spa
|
+ } |
+ |
+ // Show information about DER-encoded data representing an X509 certificate. |
+ private void showCertificate(byte[] der_data) { |
+ addCert(der_data); |
+ showDialogForView(mViews.get(0)); |
+ } |
+ |
+ // Show information about an array of DER-encoded data representing a X509 certificate chain. |
+ // A spinner will be displayed allowing the user to select which certificate to display. |
+ private void showCertificateChain(byte[][] der_data) { |
+ for (int i = 0; i < der_data.length; ++i) { |
Ted C
2013/01/25 02:04:05
i++ in java land (applicable other places in this
Yaron
2013/01/25 19:25:17
Done.
|
+ addCert(der_data[i]); |
+ } |
+ ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(mContext, |
+ android.R.layout.simple_spinner_item, |
+ mTitles); |
+ arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
+ |
+ Spinner spinner = new Spinner(mContext); |
+ spinner.setAdapter(arrayAdapter); |
+ spinner.setOnItemSelectedListener(this); |
+ |
+ LinearLayout container = new LinearLayout(mContext); |
+ container.setOrientation(LinearLayout.VERTICAL); |
+ container.addView(spinner); |
+ |
+ for (int i = 0; i < mViews.size(); ++i) { |
+ LinearLayout certificateView = mViews.get(i); |
+ if (i != 0) { |
+ certificateView.setVisibility(LinearLayout.GONE); |
+ } |
+ container.addView(certificateView); |
+ } |
+ |
+ showDialogForView(container); |
+ } |
+ |
+ // Displays a dialog with scrolling for the given view. |
+ private void showDialogForView(View view) { |
+ Dialog dialog = new Dialog(mContext); |
+ dialog.setTitle(R.string.certtitle); |
+ ScrollView scrollView = new ScrollView(mContext); |
+ scrollView.addView(view); |
+ dialog.addContentView(scrollView, |
+ new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, |
+ LinearLayout.LayoutParams.MATCH_PARENT)); |
Ted C
2013/01/25 02:04:05
should be indented 8 from the start of the line.
Yaron
2013/01/25 19:25:17
Done.
|
+ dialog.show(); |
+ } |
+ |
+ private void addCert(byte[] der_data) { |
+ try { |
+ if (mCertificateFactory == null) { |
+ mCertificateFactory = CertificateFactory.getInstance("X.509"); |
Ted C
2013/01/25 02:04:05
should X.509 be a constant?
Yaron
2013/01/25 19:25:17
Done.
|
+ } |
+ Certificate cert = mCertificateFactory.generateCertificate( |
+ new ByteArrayInputStream(der_data)); |
+ addCertDetails(cert); |
+ } catch (CertificateException e) { |
+ Log.e("CertViewer", "Error parsing certificate" + e.toString()); |
+ } |
+ } |
+ |
+ private void addCertDetails(Certificate cert) { |
+ LinearLayout certificateView = new LinearLayout(mContext); |
+ mViews.add(certificateView); |
+ certificateView.setOrientation(LinearLayout.VERTICAL); |
+ |
+ X509Certificate x509 = (X509Certificate)cert; |
Ted C
2013/01/25 02:04:05
space between the cast and the variable.
Yaron
2013/01/25 19:25:17
Done.
|
+ SslCertificate sslCert = new SslCertificate(x509); |
+ |
+ mTitles.add(sslCert.getIssuedTo().getCName()); |
+ |
+ addSectionTitle(certificateView, R.string.certissuedto); |
+ addItem(certificateView, R.string.certcn, sslCert.getIssuedTo().getCName()); |
+ addItem(certificateView, R.string.certo, sslCert.getIssuedTo().getOName()); |
+ addItem(certificateView, R.string.certou, sslCert.getIssuedTo().getUName()); |
+ addItem(certificateView, R.string.certsn, |
+ formatSerial(x509.getSerialNumber().toByteArray())); |
+ |
+ addSectionTitle(certificateView, R.string.certissuedby); |
+ addItem(certificateView, R.string.certcn, sslCert.getIssuedBy().getCName()); |
+ addItem(certificateView, R.string.certo, sslCert.getIssuedBy().getOName()); |
+ addItem(certificateView, R.string.certou, sslCert.getIssuedBy().getUName()); |
+ |
+ addSectionTitle(certificateView, R.string.certvalidity); |
+ java.text.DateFormat dateFormat = DateFormat.getDateFormat(mContext); |
+ addItem(certificateView, R.string.certissuedon, |
+ dateFormat.format(sslCert.getValidNotBeforeDate())); |
+ addItem(certificateView, R.string.certexpireson, |
+ dateFormat.format(sslCert.getValidNotAfterDate())); |
+ } |
+ |
+ private void addSectionTitle(LinearLayout certificateView, int label) { |
+ TextView title = addLabel(certificateView, label); |
+ title.setAllCaps(true); |
+ } |
+ |
+ private void addItem(LinearLayout certificateView, int label, String value) { |
+ if (!value.isEmpty()) { |
Ted C
2013/01/25 02:04:05
I would probably do if (value.isEmpty()) return;
Yaron
2013/01/25 19:25:17
Done.
|
+ addLabel(certificateView, label); |
+ addValue(certificateView, value); |
+ } |
+ } |
+ |
+ private TextView addLabel(LinearLayout certificateView, int label) { |
+ TextView t = new TextView(mContext); |
+ t.setPadding(mPadding, mPadding / 2, mPadding, 0); |
+ t.setText(label); |
+ t.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); |
+ certificateView.addView(t); |
+ return t; |
+ } |
+ |
+ private void addValue(LinearLayout certificateView, String value) { |
+ TextView t = new TextView(mContext); |
+ t.setText(value); |
+ t.setPadding(mPadding, 0, mPadding, mPadding / 2); |
+ certificateView.addView(t); |
+ } |
+ |
+ static private String formatSerial(byte[] bytes) { |
Ted C
2013/01/25 02:04:05
private before static.
Yaron
2013/01/25 19:25:17
Done.
|
+ StringBuilder sb = new StringBuilder(); |
+ for (int i = 0; i < bytes.length; i++) { |
+ sb.append(String.format("%02X", bytes[i])); |
+ if (i != bytes.length - 1) { |
+ sb.append(':'); |
+ } |
+ } |
+ return sb.toString(); |
+ } |
+ |
+ @Override |
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { |
+ for (int i = 0; i < mViews.size(); ++i) { |
+ mViews.get(i).setVisibility( |
+ i == position ? LinearLayout.VISIBLE : LinearLayout.GONE); |
+ } |
+ |
+ } |
+ |
+ @Override |
+ public void onNothingSelected(AdapterView<?> parent) { |
+ } |
+} |