diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-29 21:59:17 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-29 21:59:17 +0000 |
commit | 0fd776c40893cb7c9e02c0060a818a7fe972f1aa (patch) | |
tree | 601700d589a09e12faf4c959d8b2b40bfd3b6432 | |
parent | 808ae47cffd55a3d761151eb4da93a5befefd922 (diff) | |
download | chromium_src-0fd776c40893cb7c9e02c0060a818a7fe972f1aa.zip chromium_src-0fd776c40893cb7c9e02c0060a818a7fe972f1aa.tar.gz chromium_src-0fd776c40893cb7c9e02c0060a818a7fe972f1aa.tar.bz2 |
DOMUI options: NSS Certificate manager part 1 (read only)
BUG=19991
TEST=run with --enable-tabbed-options, click certificate manager button in options
Review URL: http://codereview.chromium.org/3389001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@60996 0039d316-1c4b-4281-b951-d872f2087c98
18 files changed, 847 insertions, 21 deletions
diff --git a/app/l10n_util_collator.h b/app/l10n_util_collator.h index 98011d9..d5b3f81 100644 --- a/app/l10n_util_collator.h +++ b/app/l10n_util_collator.h @@ -20,6 +20,9 @@ namespace l10n_util { UCollationResult CompareStringWithCollator(const icu::Collator* collator, const std::wstring& lhs, const std::wstring& rhs); +UCollationResult CompareString16WithCollator(const icu::Collator* collator, + const string16& lhs, + const string16& rhs); // Used by SortStringsUsingMethod. Invokes a method on the objects passed to // operator (), comparing the string results using a collator. diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index b5748b0..75be640 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -3139,8 +3139,8 @@ each locale. --> <message name="IDS_CERT_MANAGER_NAME_COLUMN_LABEL" desc="Label for the certificate name column of the certificate tree in the certificate manager"> Certificate Name </message> - <message name="IDS_CERT_MANAGER_DEVICE_COLUMN_LABEL" desc="Label for the security device column of the certificate tree in the certificate manager"> - Security Device + <message name="IDS_CERT_MANAGER_DEVICE_COLUMN_LABEL" desc="Label for the certificate store column of the certificate tree in the certificate manager"> + Certificate Store </message> <message name="IDS_CERT_MANAGER_SERIAL_NUMBER_COLUMN_LABEL" desc="Label for the serial number column of the certificate tree in the certificate manager"> Serial Number @@ -3152,7 +3152,7 @@ each locale. --> Email Address </message> <message name="IDS_CERT_MANAGER_VIEW_CERT_BUTTON" desc="Label for the button in the certificate manager which launches the certificate viewer for the selected certificate"> - &View + View </message> <!-- Add Client Certificate Dialog --> diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc new file mode 100644 index 0000000..170bc7a --- /dev/null +++ b/chrome/browser/certificate_manager_model.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2010 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. + +#include "chrome/browser/certificate_manager_model.h" + +#include <cert.h> + +#include "base/i18n/time_formatting.h" +#include "base/logging.h" +#include "base/utf_string_conversions.h" +#include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h" +#include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h" +#include "net/base/x509_certificate.h" + +// TODO(mattm): Try to make this use only X509Certificate stuff rather than NSS +// functions in some places. (Not very important at this time since this is only +// used w/NSS anyway.) + +// PSM = Mozilla's Personal Security Manager. +namespace psm = mozilla_security_manager; + +namespace { + +// Convert a char* return value from NSS into a std::string and free the NSS +// memory. If the arg is NULL, an empty string will be returned instead. +std::string Stringize(char* nss_text) { + std::string s; + if (nss_text) { + s = nss_text; + PORT_Free(nss_text); + } + return s; +} + +std::string GetCertNameOrNickname(CERTCertificate* os_cert) { + std::string name = psm::ProcessIDN( + Stringize(CERT_GetCommonName(&os_cert->subject))); + if (name.empty() && os_cert->nickname) { + name = os_cert->nickname; + // Hack copied from mozilla: Cut off text before first :, which seems to + // just be the token name. + size_t colon_pos = name.find(':'); + if (colon_pos != std::string::npos) + name = name.substr(colon_pos + 1); + } + return name; +} + +} // namespace + +CertificateManagerModel::CertificateManagerModel() { +} + +CertificateManagerModel::~CertificateManagerModel() { +} + +void CertificateManagerModel::Refresh() { + cert_db_.ListCerts(&cert_list_); +} + +void CertificateManagerModel::FilterAndBuildOrgGroupingMap( + net::CertType filter_type, + CertificateManagerModel::OrgGroupingMap* map) const { + for (net::CertificateList::const_iterator i = cert_list_.begin(); + i != cert_list_.end(); ++i) { + net::X509Certificate* cert = i->get(); + net::CertType type = psm::GetCertType(cert->os_cert_handle()); + if (type != filter_type) + continue; + + std::string org; + if (!cert->subject().organization_names.empty()) + org = cert->subject().organization_names[0]; + if (org.empty()) + org = cert->subject().GetDisplayName(); + + (*map)[org].push_back(cert); + } +} + +string16 CertificateManagerModel::GetColumnText( + const net::X509Certificate& cert, + Column column) const { + string16 rv; + switch (column) { + case COL_SUBJECT_NAME: + rv = UTF8ToUTF16(GetCertNameOrNickname(cert.os_cert_handle())); + break; + case COL_CERTIFICATE_STORE: + rv = UTF8ToUTF16(psm::GetCertTokenName(cert.os_cert_handle())); + break; + case COL_SERIAL_NUMBER: + rv = ASCIIToUTF16(Stringize(CERT_Hexify( + &cert.os_cert_handle()->serialNumber, PR_TRUE))); + break; + case COL_EXPIRES_ON: + if (!cert.valid_expiry().is_null()) { + rv = WideToUTF16Hack( + base::TimeFormatShortDateNumeric(cert.valid_expiry())); + } + break; + case COL_EMAIL_ADDRESS: + if (cert.os_cert_handle()->emailAddr) + rv = UTF8ToUTF16(cert.os_cert_handle()->emailAddr); + break; + default: + NOTREACHED(); + } + return rv; +} diff --git a/chrome/browser/certificate_manager_model.h b/chrome/browser/certificate_manager_model.h new file mode 100644 index 0000000..ce45d3a --- /dev/null +++ b/chrome/browser/certificate_manager_model.h @@ -0,0 +1,54 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_ +#define CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_ + +#include <map> +#include <string> + +#include "base/ref_counted.h" +#include "base/string16.h" +#include "net/base/cert_database.h" + +// CertificateManagerModel provides the data to be displayed in the certificate +// manager dialog, and processes changes from the view. +class CertificateManagerModel { + public: + // Map from the subject organization name to the list of certs from that + // organization. If a cert does not have an organization name, the + // subject's CertPrincipal::GetDisplayName() value is used instead. + typedef std::map<std::string, net::CertificateList> OrgGroupingMap; + + // Enumeration of the possible columns in the certificate manager tree view. + enum Column { + COL_SUBJECT_NAME, + COL_CERTIFICATE_STORE, + COL_SERIAL_NUMBER, + COL_EXPIRES_ON, + COL_EMAIL_ADDRESS, + }; + + CertificateManagerModel(); + ~CertificateManagerModel(); + + // Refresh the list of certs. Following this call, the view should call + // FilterAndBuildOrgGroupingMap as necessary to refresh its tree views. + void Refresh(); + + // Fill |map| with the certificates matching |filter_type|. + void FilterAndBuildOrgGroupingMap(net::CertType filter_type, + OrgGroupingMap* map) const; + + // Get the data to be displayed in |column| for the given |cert|. + string16 GetColumnText(const net::X509Certificate& cert, Column column) const; + + private: + net::CertDatabase cert_db_; + net::CertificateList cert_list_; + + DISALLOW_COPY_AND_ASSIGN(CertificateManagerModel); +}; + +#endif // CHROME_BROWSER_CERTIFICATE_MANAGER_MODEL_H_ diff --git a/chrome/browser/dom_ui/advanced_options_handler.cc b/chrome/browser/dom_ui/advanced_options_handler.cc index b64f736..778dab6 100644 --- a/chrome/browser/dom_ui/advanced_options_handler.cc +++ b/chrome/browser/dom_ui/advanced_options_handler.cc @@ -205,10 +205,12 @@ void AdvancedOptionsHandler::RegisterMessages() { dom_ui_->RegisterMessageCallback("metricsReportingCheckboxAction", NewCallback(this, &AdvancedOptionsHandler::HandleMetricsReportingCheckbox)); -#if !defined(OS_CHROMEOS) +#if !defined(USE_NSS) dom_ui_->RegisterMessageCallback("showManageSSLCertificates", NewCallback(this, &AdvancedOptionsHandler::ShowManageSSLCertificates)); +#endif +#if !defined(OS_CHROMEOS) dom_ui_->RegisterMessageCallback("showNetworkProxySettings", NewCallback(this, &AdvancedOptionsHandler::ShowNetworkProxySettings)); @@ -322,7 +324,9 @@ void AdvancedOptionsHandler::ShowNetworkProxySettings(const ListValue* args) { UserMetricsRecordAction(UserMetricsAction("Options_ShowProxySettings")); AdvancedOptionsUtilities::ShowNetworkProxySettings(dom_ui_->tab_contents()); } +#endif +#if !defined(USE_NSS) void AdvancedOptionsHandler::ShowManageSSLCertificates(const ListValue* args) { UserMetricsRecordAction(UserMetricsAction("Options_ManageSSLCertificates")); AdvancedOptionsUtilities::ShowManageSSLCertificates(dom_ui_->tab_contents()); diff --git a/chrome/browser/dom_ui/advanced_options_handler.h b/chrome/browser/dom_ui/advanced_options_handler.h index 2896d97..f85ec2a 100644 --- a/chrome/browser/dom_ui/advanced_options_handler.h +++ b/chrome/browser/dom_ui/advanced_options_handler.h @@ -70,7 +70,9 @@ class AdvancedOptionsHandler // Callback for the "showNetworkProxySettings" message. This will invoke // an appropriate dialog for configuring proxy settings. void ShowNetworkProxySettings(const ListValue* args); +#endif +#if !defined(USE_NSS) // Callback for the "showManageSSLCertificates" message. This will invoke // an appropriate certificate management action based on the platform. void ShowManageSSLCertificates(const ListValue* args); diff --git a/chrome/browser/dom_ui/advanced_options_utils_gtk.cc b/chrome/browser/dom_ui/advanced_options_utils_gtk.cc index 7226f61..b471616 100644 --- a/chrome/browser/dom_ui/advanced_options_utils_gtk.cc +++ b/chrome/browser/dom_ui/advanced_options_utils_gtk.cc @@ -29,11 +29,6 @@ const char* kKDE4ProxyConfigCommand[] = {"kcmshell4", "proxy", NULL}; // supported desktop environment. const char kLinuxProxyConfigUrl[] = "about:linux-proxy-config"; -// The URL for Linux ssl certificate configuration help. -const char* const kLinuxCertificatesConfigUrl = - "http://code.google.com/p/chromium/wiki/LinuxCertManagement"; - - struct ProxyConfigCommand { std::string binary; const char** argv; @@ -123,10 +118,4 @@ void AdvancedOptionsUtilities::ShowNetworkProxySettings( } } -void AdvancedOptionsUtilities::ShowManageSSLCertificates( - TabContents* tab_contents) { - tab_contents->OpenURL(GURL(kLinuxCertificatesConfigUrl), GURL(), - NEW_FOREGROUND_TAB, PageTransition::LINK); -} - #endif // !defined(OS_CHROMEOS) diff --git a/chrome/browser/dom_ui/certificate_manager_handler.cc b/chrome/browser/dom_ui/certificate_manager_handler.cc new file mode 100644 index 0000000..08d5641 --- /dev/null +++ b/chrome/browser/dom_ui/certificate_manager_handler.cc @@ -0,0 +1,225 @@ +// Copyright (c) 2010 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. + +#include "chrome/browser/dom_ui/certificate_manager_handler.h" + +#include "app/l10n_util.h" +#include "app/l10n_util_collator.h" +#include "base/string_number_conversions.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/certificate_manager_model.h" +#include "chrome/browser/certificate_viewer.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_contents_view.h" +#include "grit/generated_resources.h" +#include "net/base/x509_certificate.h" + +namespace { + +static const char kKeyId[] = "id"; +static const char kSubNodesId[] = "subnodes"; +static const char kNameId[] = "name"; +static const char kIconId[] = "icon"; +static const char kSecurityDeviceId[] = "device"; + +// TODO(mattm): These are duplicated from cookies_view_handler.cc +// Encodes a pointer value into a hex string. +std::string PointerToHexString(const void* pointer) { + return base::HexEncode(&pointer, sizeof(pointer)); +} + +// Decodes a pointer from a hex string. +void* HexStringToPointer(const std::string& str) { + std::vector<uint8> buffer; + if (!base::HexStringToBytes(str, &buffer) || + buffer.size() != sizeof(void*)) { + return NULL; + } + + return *reinterpret_cast<void**>(&buffer[0]); +} + +std::string OrgNameToId(const std::string& org) { + return "org-" + org; +} + +std::string CertToId(const net::X509Certificate& cert) { + return "cert-" + PointerToHexString(&cert); +} + +net::X509Certificate* IdToCert(const std::string& id) { + if (!StartsWithASCII(id, "cert-", true)) + return NULL; + return reinterpret_cast<net::X509Certificate*>(HexStringToPointer(id.substr(5))); +} + +struct DictionaryIdComparator { + DictionaryIdComparator(icu::Collator* collator) : collator_(collator) { + } + + bool operator()(const Value* a, + const Value* b) const { + DCHECK(a->GetType() == Value::TYPE_DICTIONARY); + DCHECK(b->GetType() == Value::TYPE_DICTIONARY); + const DictionaryValue* a_dict = reinterpret_cast<const DictionaryValue*>(a); + const DictionaryValue* b_dict = reinterpret_cast<const DictionaryValue*>(b); + string16 a_str; + string16 b_str; + a_dict->GetString(kNameId, &a_str); + b_dict->GetString(kNameId, &b_str); + if (collator_ == NULL) + return a_str < b_str; + return l10n_util::CompareString16WithCollator( + collator_, a_str, b_str) == UCOL_LESS; + } + + icu::Collator* collator_; +}; + +} // namespace + +CertificateManagerHandler::CertificateManagerHandler() { + certificate_manager_model_.reset(new CertificateManagerModel); +} + +CertificateManagerHandler::~CertificateManagerHandler() { +} + +void CertificateManagerHandler::GetLocalizedValues( + DictionaryValue* localized_strings) { + DCHECK(localized_strings); + + localized_strings->SetString("certificateManagerPage", + l10n_util::GetStringUTF16(IDS_CERTIFICATE_MANAGER_TITLE)); + + // Tabs. + localized_strings->SetString("personalCertsTabTitle", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PERSONAL_CERTS_TAB_LABEL)); + localized_strings->SetString("emailCertsTabTitle", + l10n_util::GetStringUTF16( + IDS_CERT_MANAGER_OTHER_PEOPLES_CERTS_TAB_LABEL)); + localized_strings->SetString("serverCertsTabTitle", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_CERTS_TAB_LABEL)); + localized_strings->SetString("caCertsTabTitle", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CERT_AUTHORITIES_TAB_LABEL)); + localized_strings->SetString("unknownCertsTabTitle", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNKNOWN_TAB_LABEL)); + + // Tab descriptions. + localized_strings->SetString("personalCertsTabDescription", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_USER_TREE_DESCRIPTION)); + localized_strings->SetString("emailCertsTabDescription", + l10n_util::GetStringUTF16( + IDS_CERT_MANAGER_OTHER_PEOPLE_TREE_DESCRIPTION)); + localized_strings->SetString("serverCertsTabDescription", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_TREE_DESCRIPTION)); + localized_strings->SetString("caCertsTabDescription", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_AUTHORITIES_TREE_DESCRIPTION)); + localized_strings->SetString("unknownCertsTabDescription", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNKNOWN_TREE_DESCRIPTION)); + + // Tree columns. + localized_strings->SetString("certNameColumn", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_NAME_COLUMN_LABEL)); + localized_strings->SetString("certDeviceColumn", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DEVICE_COLUMN_LABEL)); + localized_strings->SetString("certSerialColumn", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERIAL_NUMBER_COLUMN_LABEL)); + localized_strings->SetString("certExpiresColumn", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPIRES_COLUMN_LABEL)); + localized_strings->SetString("certEmailColumn", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EMAIL_ADDRESS_COLUMN_LABEL)); + + // Buttons. + localized_strings->SetString("view_certificate", + l10n_util::GetStringUTF16(IDS_CERT_MANAGER_VIEW_CERT_BUTTON)); +} + +void CertificateManagerHandler::RegisterMessages() { + dom_ui_->RegisterMessageCallback("viewCertificate", + NewCallback(this, &CertificateManagerHandler::View)); + + dom_ui_->RegisterMessageCallback("populateCertificateManager", + NewCallback(this, &CertificateManagerHandler::Populate)); +} + +void CertificateManagerHandler::View(const ListValue* args) { + std::string node_id; + if (!args->GetString(0, &node_id)){ + return; + } + net::X509Certificate* cert = IdToCert(node_id); + if (!cert) { + NOTREACHED(); + return; + } + ShowCertificateViewer( + dom_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), cert); +} + +void CertificateManagerHandler::Populate(const ListValue* args) { + certificate_manager_model_->Refresh(); + + PopulateTree("personalCertsTab", net::USER_CERT); + PopulateTree("emailCertsTab", net::EMAIL_CERT); + PopulateTree("serverCertsTab", net::SERVER_CERT); + PopulateTree("caCertsTab", net::CA_CERT); + PopulateTree("otherCertsTab", net::UNKNOWN_CERT); +} + +void CertificateManagerHandler::PopulateTree(const std::string& tab_name, + net::CertType type) { + const std::string tree_name = tab_name + "-tree"; + + scoped_ptr<icu::Collator> collator; + UErrorCode error = U_ZERO_ERROR; + collator.reset( + icu::Collator::createInstance( + icu::Locale(g_browser_process->GetApplicationLocale().c_str()), + error)); + if (U_FAILURE(error)) + collator.reset(NULL); + DictionaryIdComparator comparator(collator.get()); + CertificateManagerModel::OrgGroupingMap map; + + certificate_manager_model_->FilterAndBuildOrgGroupingMap(type, &map); + + { + ListValue* nodes = new ListValue; + for (CertificateManagerModel::OrgGroupingMap::iterator i = map.begin(); + i != map.end(); ++i) { + // Populate first level (org name). + DictionaryValue* dict = new DictionaryValue; + dict->SetString(kKeyId, OrgNameToId(i->first)); + dict->SetString(kNameId, i->first); + + // Populate second level (certs). + ListValue* subnodes = new ListValue; + for (net::CertificateList::const_iterator org_cert_it = i->second.begin(); + org_cert_it != i->second.end(); ++org_cert_it) { + DictionaryValue* cert_dict = new DictionaryValue; + net::X509Certificate* cert = org_cert_it->get(); + cert_dict->SetString(kKeyId, CertToId(*cert)); + cert_dict->SetString(kNameId, certificate_manager_model_->GetColumnText( + *cert, CertificateManagerModel::COL_SUBJECT_NAME)); + // TODO(mattm): Other columns. + // TODO(mattm): Get a real icon (or figure out how to make the domui + // tree not use icons at all). + cert_dict->SetString(kIconId, "chrome://theme/IDR_COOKIE_ICON"); + subnodes->Append(cert_dict); + } + std::sort(subnodes->begin(), subnodes->end(), comparator); + + dict->Set(kSubNodesId, subnodes); + nodes->Append(dict); + } + std::sort(nodes->begin(), nodes->end(), comparator); + + ListValue args; + args.Append(Value::CreateStringValue(tree_name)); + args.Append(nodes); + dom_ui_->CallJavascriptFunction(L"CertificateManager.onPopulateTree", args); + } +} diff --git a/chrome/browser/dom_ui/certificate_manager_handler.h b/chrome/browser/dom_ui/certificate_manager_handler.h new file mode 100644 index 0000000..265dba4 --- /dev/null +++ b/chrome/browser/dom_ui/certificate_manager_handler.h @@ -0,0 +1,40 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_DOM_UI_CERTIFICATE_MANAGER_HANDLER_H_ +#define CHROME_BROWSER_DOM_UI_CERTIFICATE_MANAGER_HANDLER_H_ +#pragma once + +#include "base/scoped_ptr.h" +#include "chrome/browser/dom_ui/options_ui.h" +#include "net/base/cert_database.h" + +class CertificateManagerModel; + +class CertificateManagerHandler : public OptionsPageUIHandler { + public: + CertificateManagerHandler(); + virtual ~CertificateManagerHandler(); + + // OptionsUIHandler implementation. + virtual void GetLocalizedValues(DictionaryValue* localized_strings); + virtual void RegisterMessages(); + + private: + // View certificate. + void View(const ListValue* args); + + // Populate the trees in all the tabs. + void Populate(const ListValue* args); + + // Populate the given tab's tree. + void PopulateTree(const std::string& tab_name, net::CertType type); + + // The Certificates Manager model + scoped_ptr<CertificateManagerModel> certificate_manager_model_; + + DISALLOW_COPY_AND_ASSIGN(CertificateManagerHandler); +}; + +#endif // CHROME_BROWSER_DOM_UI_CERTIFICATE_MANAGER_HANDLER_H_ diff --git a/chrome/browser/dom_ui/options_ui.cc b/chrome/browser/dom_ui/options_ui.cc index cb7830a..0ebeba8 100644 --- a/chrome/browser/dom_ui/options_ui.cc +++ b/chrome/browser/dom_ui/options_ui.cc @@ -65,6 +65,10 @@ #include "chrome/browser/chromeos/dom_ui/system_options_handler.h" #endif +#if defined(USE_NSS) +#include "chrome/browser/dom_ui/certificate_manager_handler.h" +#endif + //////////////////////////////////////////////////////////////////////////////// // // OptionsUIHTMLSource @@ -162,6 +166,9 @@ OptionsUI::OptionsUI(TabContents* contents) : DOMUI(contents) { AddOptionsPageUIHandler(localized_strings, new chromeos::ProxyHandler()); AddOptionsPageUIHandler(localized_strings, new SystemOptionsHandler()); #endif +#if defined(USE_NSS) + AddOptionsPageUIHandler(localized_strings, new CertificateManagerHandler()); +#endif // |localized_strings| ownership is taken over by this constructor. OptionsUIHTMLSource* html_source = diff --git a/chrome/browser/resources/options.html b/chrome/browser/resources/options.html index 74cd3bc..d6be2f9f 100644 --- a/chrome/browser/resources/options.html +++ b/chrome/browser/resources/options.html @@ -34,6 +34,10 @@ <link rel="stylesheet" href="options/chromeos_language_options.css"> </if> +<if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')"> + <link rel="stylesheet" href="options/certificate_manager.css"> +</if> + <script src="chrome://resources/css/tree.css.js"></script> <script src="chrome://resources/js/class_list.js"></script> @@ -75,6 +79,13 @@ var SystemOptions = options.SystemOptions; </script> </if> +<if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')"> + <script src="options/certificate_tree.js"></script> + <script src="options/certificate_manager.js"></script> + <script> + var CertificateManager = options.CertificateManager; + </script> +</if> <script src="options/add_startup_page_overlay.js"></script> <script src="options/add_startup_page_recent_pages_list.js"></script> <script src="options/advanced_options.js"></script> @@ -146,6 +157,9 @@ function load() { OptionsPage.registerSubPage(PasswordsExceptions.getInstance()); OptionsPage.registerSubPage(SearchEngineManager.getInstance()); OptionsPage.registerSubPage(SyncOptions.getInstance()); + if (!cr.isWindows && !cr.isMac) { + OptionsPage.registerSubPage(CertificateManager.getInstance()); + } OptionsPage.registerOverlay(AddStartupPageOverlay.getInstance()); OptionsPage.registerOverlay(AlertOverlay.getInstance()); OptionsPage.registerOverlay(AutoFillEditAddressOverlay.getInstance()); @@ -275,6 +289,9 @@ window.onpopstate = function(e) { <include src="options/chromeos_accounts_options.html"> <include src="options/chromeos_proxy.html"> </if> + <if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')"> + <include src="options/certificate_manager.html"> + </if> <include src="options/advanced_options.html"> <include src="options/autofill_options.html"> <include src="options/browser_options.html"> diff --git a/chrome/browser/resources/options/advanced_options.html b/chrome/browser/resources/options/advanced_options.html index 8faf6ed..349ed38 100644 --- a/chrome/browser/resources/options/advanced_options.html +++ b/chrome/browser/resources/options/advanced_options.html @@ -90,14 +90,12 @@ </if> </div> </section> -<if expr="not pp_ifdef('chromeos')"> <section> <h3 i18n-content="advancedSectionTitleSecurity"></h3> <div> <div i18n-content="certificatesLabel"></div> <div><button id="certificatesManageButton" i18n-content="certificatesManageButton"></button></div> -</if> <if expr="os == 'win32'"> <!-- Configure these options for manual handling on windows --> <label><input id="sslCheckRevocation" @@ -123,9 +121,9 @@ pref="ssl.tls1.enabled" metric="Options_TLS1" type="checkbox"><span i18n-content="sslUseTLS1"></span></label> </if> -<if expr="not pp_ifdef('chromeos')"> </div> </section> +<if expr="not pp_ifdef('chromeos')"> <section id="background-mode-section"> <h3 i18n-content="advancedSectionTitleChromeApps"></h3> <div> diff --git a/chrome/browser/resources/options/advanced_options.js b/chrome/browser/resources/options/advanced_options.js index 64011ce..dabb324 100644 --- a/chrome/browser/resources/options/advanced_options.js +++ b/chrome/browser/resources/options/advanced_options.js @@ -54,6 +54,18 @@ var OptionsPage = options.OptionsPage; OptionsPage.showPageByName('fontSettings'); chrome.send('coreOptionsUserMetricsAction', ['Options_FontSettings']); }; + if (cr.isWindows || cr.isMac) { + $('certificatesManageButton').onclick = function(event) { + chrome.send('showManageSSLCertificates'); + }; + } else { + $('certificatesManageButton').onclick = function(event) { + OptionsPage.showPageByName('certificateManager'); + OptionsPage.showTab($('personal-certs-nav-tab')); + chrome.send('coreOptionsUserMetricsAction', + ['Options_ManageSSLCertificates']); + }; + } if (!cr.isChromeOS) { $('optionsReset').onclick = function(event) { AlertOverlay.show(undefined, @@ -65,9 +77,6 @@ var OptionsPage = options.OptionsPage; $('proxiesConfigureButton').onclick = function(event) { chrome.send('showNetworkProxySettings'); }; - $('certificatesManageButton').onclick = function(event) { - chrome.send('showManageSSLCertificates'); - }; $('downloadLocationBrowseButton').onclick = function(event) { chrome.send('selectDownloadLocation'); }; diff --git a/chrome/browser/resources/options/certificate_manager.css b/chrome/browser/resources/options/certificate_manager.css new file mode 100644 index 0000000..a88d231 --- /dev/null +++ b/chrome/browser/resources/options/certificate_manager.css @@ -0,0 +1,15 @@ +/* +Copyright (c) 2010 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. +*/ + +.certificate-tree-table { + width: 100%; +} + +.certificate-tree { + /* TODO(mattm): BLAH. Make this not statically sized. */ + height: 300px; +} + diff --git a/chrome/browser/resources/options/certificate_manager.html b/chrome/browser/resources/options/certificate_manager.html new file mode 100644 index 0000000..32821f2 --- /dev/null +++ b/chrome/browser/resources/options/certificate_manager.html @@ -0,0 +1,106 @@ +<div class="page hidden" id="certificateManagerPage"> + <h1> + <span i18n-content="advancedPage"></span> + > + <span i18n-content="certificateManagerPage"></span> + </h1> + + <!-- Navigation tabs --> + <div class="subpages-nav-tabs"> + <span i18n-content="personalCertsTabTitle" id="personal-certs-nav-tab" + class="inactive-tab" tab-contents="personalCertsTab"></span><span + i18n-content="emailCertsTabTitle" id="email-certs-nav-tab" + class="inactive-tab" tab-contents="emailCertsTab"></span><span + i18n-content="serverCertsTabTitle" id="server-certs-nav-tab" + class="inactive-tab" tab-contents="serverCertsTab"></span><span + i18n-content="caCertsTabTitle" id="ca-certs-nav-tab" + class="inactive-tab" tab-contents="caCertsTab"></span><span + i18n-content="unknownCertsTabTitle" id="other-certs-nav-tab" + class="inactive-tab" tab-contents="otherCertsTab"></span> + </div> + + <!-- TODO(mattm): get rid of use of tables? --> + + <!-- Tab contents --> + <div id="personalCertsTab" class="subpages-tab-contents"> + <table class="certificate-tree-table"> + <tr><td> + <span i18n-content="personalCertsTabDescription"></span> + </td></tr> + <tr><td> + <tree id="personalCertsTab-tree" class="certificate-tree"></tree> + </td></tr> + <tr><td> + <button id="personalCertsTab-view" i18n-content="view_certificate" + disabled></button> + <!-- TODO other buttons --> + </td></tr> + </table> + </div> + + <div id="emailCertsTab" class="subpages-tab-contents"> + <table class="certificate-tree-table"> + <tr><td> + <span i18n-content="emailCertsTabDescription"></span> + </td></tr> + <tr><td> + <tree id="emailCertsTab-tree" class="certificate-tree"></tree> + </td></tr> + <tr><td> + <button id="emailCertsTab-view" i18n-content="view_certificate" + disabled></button> + <!-- TODO other buttons --> + </td></tr> + </table> + </div> + + <div id="serverCertsTab" class="subpages-tab-contents"> + <table class="certificate-tree-table"> + <tr><td> + <span i18n-content="serverCertsTabDescription"></span> + </td></tr> + <tr><td> + <tree id="serverCertsTab-tree" class="certificate-tree"></tree> + </td></tr> + <tr><td> + <button id="serverCertsTab-view" i18n-content="view_certificate" + disabled></button> + <!-- TODO other buttons --> + </td></tr> + </table> + </div> + + <div id="caCertsTab" class="subpages-tab-contents"> + <table class="certificate-tree-table"> + <tr><td> + <span i18n-content="caCertsTabDescription"></span> + </td></tr> + <tr><td> + <tree id="caCertsTab-tree" class="certificate-tree"></tree> + </td></tr> + <tr><td> + <button id="caCertsTab-view" i18n-content="view_certificate" + disabled></button> + <!-- TODO other buttons --> + </td></tr> + </table> + </div> + + <div id="otherCertsTab" class="subpages-tab-contents"> + <table class="certificate-tree-table"> + <tr><td> + <span i18n-content="unknownCertsTabDescription"></span> + </td></tr> + <tr><td> + <tree id="otherCertsTab-tree" class="certificate-tree"></tree> + </td></tr> + <tr><td> + <button id="otherCertsTab-view" i18n-content="view_certificate" + disabled></button> + <!-- TODO other buttons --> + </td></tr> + </table> + </div> + +</div> + diff --git a/chrome/browser/resources/options/certificate_manager.js b/chrome/browser/resources/options/certificate_manager.js new file mode 100644 index 0000000..741809e --- /dev/null +++ b/chrome/browser/resources/options/certificate_manager.js @@ -0,0 +1,117 @@ +// Copyright (c) 2010 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. + +cr.define('options', function() { + + var OptionsPage = options.OptionsPage; + + ///////////////////////////////////////////////////////////////////////////// + // CertificateManagerTab class: + + /** + * blah + * @param {!string} id The id of this tab. + */ + function CertificateManagerTab(id) { + this.tree = $(id + '-tree'); + + options.CertificatesTree.decorate(this.tree); + this.tree.addEventListener('change', + this.handleCertificatesTreeChange_.bind(this)); + + + this.viewButton = $(id + '-view'); + + var tree = this.tree; + this.viewButton.onclick = function(e) { + var selected = tree.selectedItem; + chrome.send('viewCertificate', [selected.data.id]); + } + } + + CertificateManagerTab.prototype = { + + /** + * Update button state. + * @private + * @param {!Object} data The data of the selected item. + */ + updateButtonState: function(data) { + var isCert = !!data && data.id.substr(0, 5) == 'cert-'; + this.viewButton.disabled = !isCert; + }, + + /** + * Handles certificate tree selection change. + * @private + * @param {!Event} e The change event object. + */ + handleCertificatesTreeChange_: function(e) { + var data = null; + if (this.tree.selectedItem) { + data = this.tree.selectedItem.data; + } + + this.updateButtonState(data); + }, + + } + + ///////////////////////////////////////////////////////////////////////////// + // CertificateManager class: + + /** + * Encapsulated handling of ChromeOS accounts options page. + * @constructor + */ + function CertificateManager(model) { + OptionsPage.call(this, 'certificateManager', + localStrings.getString('certificateManagerPage'), + 'certificateManagerPage'); + } + + cr.addSingletonGetter(CertificateManager); + + CertificateManager.prototype = { + __proto__: OptionsPage.prototype, + + initializePage: function() { + OptionsPage.prototype.initializePage.call(this); + + this.personalTab = new CertificateManagerTab('personalCertsTab'); + this.emailTab = new CertificateManagerTab('emailCertsTab'); + this.serverTab = new CertificateManagerTab('serverCertsTab'); + this.caTab = new CertificateManagerTab('caCertsTab'); + this.otherTab = new CertificateManagerTab('otherCertsTab'); + + this.addEventListener('visibleChange', this.handleVisibleChange_); + }, + + initalized_: false, + + /** + * Handler for OptionsPage's visible property change event. + * @private + * @param {Event} e Property change event. + */ + handleVisibleChange_: function(e) { + if (!this.initalized_ && this.visible) { + this.initalized_ = true; + chrome.send('populateCertificateManager'); + } + } + }; + + // CertificateManagerHandler callbacks. + CertificateManager.onPopulateTree = function(args) { + $(args[0]).populate(args[1]); + }; + + // Export + return { + CertificateManagerTab: CertificateManagerTab, + CertificateManager: CertificateManager + }; + +}); diff --git a/chrome/browser/resources/options/certificate_tree.js b/chrome/browser/resources/options/certificate_tree.js new file mode 100644 index 0000000..f8ac854 --- /dev/null +++ b/chrome/browser/resources/options/certificate_tree.js @@ -0,0 +1,120 @@ +// Copyright (c) 2010 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. + +cr.define('options', function() { + const Tree = cr.ui.Tree; + const TreeItem = cr.ui.TreeItem; + + /** + * Creates a new tree item for certificate data. + * @param {Object=} data Data used to create a certificate tree item. + * @constructor + * @extends {TreeItem} + */ + function CertificateTreeItem(data) { + // TODO(mattm): other columns + var treeItem = new TreeItem({ + label: data.name, + data: data + }); + treeItem.__proto__ = CertificateTreeItem.prototype; + + if (data.icon) { + treeItem.icon = data.icon; + } + + return treeItem; + } + + CertificateTreeItem.prototype = { + __proto__: TreeItem.prototype, + + /** + * The tree path id/. + * @type {string} + */ + get pathId() { + var parent = this.parentItem; + if (parent && parent instanceof CertificateTreeItem) { + return parent.pathId + ',' + this.data.id; + } else { + return this.data.id; + } + } + }; + + /** + * Creates a new cookies tree. + * @param {Object=} opt_propertyBag Optional properties. + * @constructor + * @extends {Tree} + */ + var CertificatesTree = cr.ui.define('tree'); + + CertificatesTree.prototype = { + __proto__: Tree.prototype, + + /** @inheritDoc */ + decorate: function() { + Tree.prototype.decorate.call(this); + this.treeLookup_ = {}; + }, + + /** @inheritDoc */ + addAt: function(child, index) { + Tree.prototype.addAt.call(this, child, index); + if (child.data && child.data.id) + this.treeLookup_[child.data.id] = child; + }, + + /** @inheritDoc */ + remove: function(child) { + Tree.prototype.remove.call(this, child); + if (child.data && child.data.id) + delete this.treeLookup_[child.data.id]; + }, + + /** + * Clears the tree. + */ + clear: function() { + // Remove all fields without recreating the object since other code + // references it. + for (var id in this.treeLookup_){ + delete this.treeLookup_[id]; + } + this.textContent = ''; + }, + + /** + * Populate the tree. + * @param {Array} nodesData Nodes data array. + */ + populate: function(nodesData) { + this.clear(); + + for (var i = 0; i < nodesData.length; ++i) { + var subnodes = nodesData[i]['subnodes']; + delete nodesData[i]['subnodes']; + + var item = new CertificateTreeItem(nodesData[i]); + this.addAt(item, i); + + for (var j = 0; j < subnodes.length; ++j) { + var subitem = new CertificateTreeItem(subnodes[j]); + item.addAt(subitem, j); + } + // Make tree expanded by default. + item.expanded = true; + } + + cr.dispatchSimpleEvent(this, 'change'); + }, + }; + + return { + CertificatesTree: CertificatesTree + }; +}); + diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index df077d3..27753ba 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -345,6 +345,8 @@ 'browser/cancelable_request.h', 'browser/cert_store.cc', 'browser/cert_store.h', + 'browser/certificate_manager_model.cc', + 'browser/certificate_manager_model.h', 'browser/certificate_viewer.cc', 'browser/certificate_viewer.h', 'browser/character_encoding.cc', @@ -1230,6 +1232,8 @@ 'browser/dom_ui/advanced_options_utils_win.cc', 'browser/dom_ui/browser_options_handler.cc', 'browser/dom_ui/browser_options_handler.h', + 'browser/dom_ui/certificate_manager_handler.cc', + 'browser/dom_ui/certificate_manager_handler.h', 'browser/dom_ui/clear_browser_data_handler.cc', 'browser/dom_ui/clear_browser_data_handler.h', 'browser/dom_ui/content_settings_handler.cc', @@ -3301,6 +3305,11 @@ ], }, { # OS != "linux" 'sources!': [ + # TODO(mattm): Cert manager stuff is really !USE_NSS. + 'browser/certificate_manager_model.cc', + 'browser/certificate_manager_model.h', + 'browser/dom_ui/certificate_manager_handler.cc', + 'browser/dom_ui/certificate_manager_handler.h', 'browser/file_path_watcher_inotify.cc', ], }], |