summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authormattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-06 21:18:07 +0000
committermattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-06 21:18:07 +0000
commit06dc32060d502c4341f61847f9f6054a110e15d5 (patch)
treeda4c46e0be11deeb3263c255ae00ce8af6effa7f /chrome
parentcc965a7964fbe747a3d8b9de9cd423fa8d13bbfc (diff)
downloadchromium_src-06dc32060d502c4341f61847f9f6054a110e15d5.zip
chromium_src-06dc32060d502c4341f61847f9f6054a110e15d5.tar.gz
chromium_src-06dc32060d502c4341f61847f9f6054a110e15d5.tar.bz2
DOMUI Certificate Manager: Backup and restore PKCS #12 files. Export certs. Delete certs.
BUG=19991 TEST=manual Review URL: http://codereview.chromium.org/3556007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61701 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/app/generated_resources.grd75
-rw-r--r--chrome/browser/certificate_manager_model.cc28
-rw-r--r--chrome/browser/certificate_manager_model.h30
-rw-r--r--chrome/browser/dom_ui/dom_ui.cc6
-rw-r--r--chrome/browser/dom_ui/dom_ui.h2
-rw-r--r--chrome/browser/dom_ui/options/certificate_manager_handler.cc460
-rw-r--r--chrome/browser/dom_ui/options/certificate_manager_handler.h85
-rw-r--r--chrome/browser/gtk/certificate_dialogs.cc6
-rw-r--r--chrome/browser/resources/options.html10
-rw-r--r--chrome/browser/resources/options/certificate_backup_overlay.html42
-rw-r--r--chrome/browser/resources/options/certificate_backup_overlay.js118
-rw-r--r--chrome/browser/resources/options/certificate_manager.html51
-rw-r--r--chrome/browser/resources/options/certificate_manager.js88
-rw-r--r--chrome/browser/resources/options/certificate_restore_overlay.html19
-rw-r--r--chrome/browser/resources/options/certificate_restore_overlay.js97
15 files changed, 1087 insertions, 30 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index c9212b4..d05c9cf 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3154,6 +3154,81 @@ each locale. -->
<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
</message>
+ <message name="IDS_CERT_MANAGER_IMPORT_BUTTON" desc="Label for the button in the certificate manager which allows you to import certificates">
+ Import...
+ </message>
+ <message name="IDS_CERT_MANAGER_EXPORT_BUTTON" desc="Label for the button in the certificate manager which allows you to export certificates">
+ Export...
+ </message>
+ <message name="IDS_CERT_MANAGER_EXPORT_ALL_BUTTON" desc="Label for the button in the certificate manager which saves all personal certificates and their private keys">
+ Export All...
+ </message>
+ <message name="IDS_CERT_MANAGER_EDIT_BUTTON" desc="Label for the button in the certificate manager which allows you to edit certificate trust">
+ Edit...
+ </message>
+ <message name="IDS_CERT_MANAGER_DELETE_BUTTON" desc="Label for the button in the certificate manager which allows you to delete certificates">
+ Delete...
+ </message>
+ <message name="IDS_CERT_MANAGER_DELETE_USER_FORMAT" desc="Confirmation in certificate manager dialog for deleting a user certificate">
+ Delete certificate "<ph name="CERTIFICATE_NAME">$1<ex>VeriSign Browser Certificate</ex></ph>"?
+ </message>
+ <message name="IDS_CERT_MANAGER_DELETE_USER_DESCRIPTION" desc="Description of impact of deleting a user certificate">
+ If you delete one of your own certificates, you can no longer use it to identify yourself.
+ </message>
+ <message name="IDS_CERT_MANAGER_DELETE_SERVER_FORMAT" desc="Confirmation in certificate manager dialog for deleting a server certificate">
+ Delete server certificate "<ph name="CERTIFICATE_NAME">$1<ex>www.example.com</ex></ph>"?
+ </message>
+ <message name="IDS_CERT_MANAGER_DELETE_SERVER_DESCRIPTION" desc="Description of impact of deleting a server certificate">
+ If you delete a server certificate, you restore the usual security checks for that server and require it uses a valid certificate.
+ </message>
+ <message name="IDS_CERT_MANAGER_DELETE_CA_FORMAT" desc="Confirmation in certificate manager dialog for deleting a certificate authority certificate">
+ Delete CA certificate "<ph name="CERTIFICATE_NAME">$1<ex>Verisign Class 1 Public Primary Certification Authority</ex></ph>"?
+ </message>
+ <message name="IDS_CERT_MANAGER_DELETE_CA_DESCRIPTION" desc="Description of impact of deleting a certificate authority certificate">
+ If you delete a Certificate Authority (CA) certificate, your browser will no longer trust any certificates issued by that CA.
+ </message>
+ <message name="IDS_CERT_MANAGER_DELETE_UNKNOWN_FORMAT" desc="Confirmation in certificate manager dialog for deleting a certificate of other type">
+ Delete certificate "<ph name="CERTIFICATE_NAME">$1<ex>Example Certificate</ex></ph>"?
+ </message>
+ <message name="IDS_CERT_MANAGER_EXPORT_PASSWORD_DESC" desc="Description of password prompt in certificate manager for exporting a personal certificate">
+ Please enter a password to encrypt this certificate file.
+ </message>
+ <message name="IDS_CERT_MANAGER_EXPORT_PASSWORD_HELP" desc="Text in password prompt of certificate manager for exporting a personal certificate, reminding user that if they forget the password they're screwed.">
+ The password you choose will be required to restore this file later. Please record it in a safe location.
+ </message>
+ <message name="IDS_CERT_MANAGER_RESTORE_PASSWORD_DESC" desc="Description of password prompt in certificate manager for restoring a personal certificate">
+ Please enter the password that was used to encrypt this certificate file.
+ </message>
+ <message name="IDS_CERT_MANAGER_PASSWORD_LABEL" desc="The label of the password field in the certificate manager for restoring or exporting a personal certificate">
+ Password:
+ </message>
+ <message name="IDS_CERT_MANAGER_CONFIRM_PASSWORD_LABEL" desc="The label of the field in the certificate manager for re-entering the password when creating a export.">
+ Confirm Password:
+ </message>
+ <message name="IDS_CERT_MANAGER_PKCS12_FILES" desc="The label in the file selector dialog for PKCS #12 file type.">
+ PKCS #12 Files
+ </message>
+ <message name="IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE" desc="The title in the error dialog for PKCS #12 file export errors.">
+ PKCS #12 Export Error
+ </message>
+ <message name="IDS_CERT_MANAGER_WRITE_ERROR_FORMAT" desc="The text in the error dialog for PKCS #12 file write errors.">
+ There was an error while trying to write the file: <ph name="ERROR_TEXT">$1<ex>Permission denied.</ex></ph>.
+ </message>
+ <message name="IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE" desc="The title in the error dialog for PKCS #12 file import errors.">
+ PKCS #12 Import Error
+ </message>
+ <message name="IDS_CERT_MANAGER_READ_ERROR_FORMAT" desc="The text in the error dialog for PKCS #12 file read errors.">
+ There was an error while trying to read the file: <ph name="ERROR_TEXT">$1<ex>File not found.</ex></ph>.
+ </message>
+ <message name="IDS_CERT_MANAGER_BAD_PASSWORD" desc="The text in the error dialog for entering an incorrect password when importing an encrypted certificate file.">
+ Incorrect password.
+ </message>
+ <message name="IDS_CERT_MANAGER_UNKNOWN_ERROR" desc="The text in the error dialog when an unknown error occurs during an operation on the certificate database.">
+ Unknown error.
+ </message>
+ <message name="IDS_CERT_MANAGER_DELETE_CERT_ERROR_TITLE" desc="The title in the error dialog for certificate delete errors.">
+ Certificate Deletion Error
+ </message>
<!-- Add Client Certificate Dialog -->
<message name="IDS_ADD_CERT_DIALOG_ADD" desc="Title of the button that adds the certificate in the Add Client Certificate dialog">
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
index 170bc7a..4cdea8b184 100644
--- a/chrome/browser/certificate_manager_model.cc
+++ b/chrome/browser/certificate_manager_model.cc
@@ -11,6 +11,7 @@
#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/net_errors.h"
#include "net/base/x509_certificate.h"
// TODO(mattm): Try to make this use only X509Certificate stuff rather than NSS
@@ -49,14 +50,18 @@ std::string GetCertNameOrNickname(CERTCertificate* os_cert) {
} // namespace
-CertificateManagerModel::CertificateManagerModel() {
+CertificateManagerModel::CertificateManagerModel(Observer* observer)
+ : observer_(observer) {
}
CertificateManagerModel::~CertificateManagerModel() {
}
void CertificateManagerModel::Refresh() {
+ VLOG(1) << "refresh started";
cert_db_.ListCerts(&cert_list_);
+ observer_->CertificatesRefreshed();
+ VLOG(1) << "refresh finished";
}
void CertificateManagerModel::FilterAndBuildOrgGroupingMap(
@@ -109,3 +114,24 @@ string16 CertificateManagerModel::GetColumnText(
}
return rv;
}
+
+int CertificateManagerModel::ImportFromPKCS12(const std::string& data,
+ const string16& password) {
+ int result = cert_db_.ImportFromPKCS12(data, password);
+ if (result == net::OK)
+ Refresh();
+ return result;
+}
+
+int CertificateManagerModel::ExportToPKCS12(const net::CertificateList& certs,
+ const string16& password,
+ std::string* output) const {
+ return cert_db_.ExportToPKCS12(certs, password, output);
+}
+
+bool CertificateManagerModel::Delete(net::X509Certificate* cert) {
+ bool result = cert_db_.DeleteCertAndKey(cert);
+ if (result)
+ Refresh();
+ return result;
+}
diff --git a/chrome/browser/certificate_manager_model.h b/chrome/browser/certificate_manager_model.h
index ce45d3a..2598bdf 100644
--- a/chrome/browser/certificate_manager_model.h
+++ b/chrome/browser/certificate_manager_model.h
@@ -30,10 +30,19 @@ class CertificateManagerModel {
COL_EMAIL_ADDRESS,
};
- CertificateManagerModel();
+ class Observer {
+ public:
+ // Called to notify the view that the certificate list has been refreshed.
+ // TODO(mattm): do a more granular updating strategy? Maybe retrieve new
+ // list of certs, diff against past list, and then notify of the changes?
+ virtual void CertificatesRefreshed() = 0;
+ };
+
+ explicit CertificateManagerModel(Observer* observer);
~CertificateManagerModel();
- // Refresh the list of certs. Following this call, the view should call
+ // Refresh the list of certs. Following this call, the observer
+ // CertificatesRefreshed method will be called so the view can call
// FilterAndBuildOrgGroupingMap as necessary to refresh its tree views.
void Refresh();
@@ -44,10 +53,27 @@ class CertificateManagerModel {
// Get the data to be displayed in |column| for the given |cert|.
string16 GetColumnText(const net::X509Certificate& cert, Column column) const;
+ // Import certificates from PKCS #12 encoded |data|, using the given
+ // |password|. Returns a net error code on failure.
+ int ImportFromPKCS12(const std::string& data, const string16& password);
+
+ // Export certificates as PKCS #12 encoded |output|, using the given
+ // |password|. Returns number of certs exported.
+ int ExportToPKCS12(const net::CertificateList& certs,
+ const string16& password,
+ std::string* output) const;
+
+ // Delete the cert. Returns true on success. |cert| is still valid when this
+ // function returns.
+ bool Delete(net::X509Certificate* cert);
+
private:
net::CertDatabase cert_db_;
net::CertificateList cert_list_;
+ // The observer to notify when certificate list is refreshed.
+ Observer* observer_;
+
DISALLOW_COPY_AND_ASSIGN(CertificateManagerModel);
};
diff --git a/chrome/browser/dom_ui/dom_ui.cc b/chrome/browser/dom_ui/dom_ui.cc
index f257d1e0..a7f5a52 100644
--- a/chrome/browser/dom_ui/dom_ui.cc
+++ b/chrome/browser/dom_ui/dom_ui.cc
@@ -111,6 +111,12 @@ void DOMUI::CallJavascriptFunction(
ExecuteJavascript(GetJavascript(function_name, args));
}
+void DOMUI::CallJavascriptFunction(
+ const std::wstring& function_name,
+ const std::vector<const Value*>& args) {
+ ExecuteJavascript(GetJavascript(function_name, args));
+}
+
ThemeProvider* DOMUI::GetThemeProvider() const {
return tab_contents_->profile()->GetThemeProvider();
}
diff --git a/chrome/browser/dom_ui/dom_ui.h b/chrome/browser/dom_ui/dom_ui.h
index d180a51..e6df31a 100644
--- a/chrome/browser/dom_ui/dom_ui.h
+++ b/chrome/browser/dom_ui/dom_ui.h
@@ -111,6 +111,8 @@ class DOMUI {
const Value& arg2,
const Value& arg3,
const Value& arg4);
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const std::vector<const Value*>& args);
ThemeProvider* GetThemeProvider() const;
diff --git a/chrome/browser/dom_ui/options/certificate_manager_handler.cc b/chrome/browser/dom_ui/options/certificate_manager_handler.cc
index b73e51c..27dc56a 100644
--- a/chrome/browser/dom_ui/options/certificate_manager_handler.cc
+++ b/chrome/browser/dom_ui/options/certificate_manager_handler.cc
@@ -6,11 +6,15 @@
#include "app/l10n_util.h"
#include "app/l10n_util_collator.h"
+#include "base/file_util.h" // for FileAccessProvider
+#include "base/safe_strerror_posix.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/chrome_thread.h" // for FileAccessProvider
+#include "chrome/browser/gtk/certificate_dialogs.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "grit/generated_resources.h"
@@ -24,6 +28,12 @@ static const char kNameId[] = "name";
static const char kIconId[] = "icon";
static const char kSecurityDeviceId[] = "device";
+// Enumeration of different callers of SelectFile.
+enum {
+ EXPORT_PERSONAL_FILE_SELECTED,
+ IMPORT_PERSONAL_FILE_SELECTED,
+};
+
// TODO(mattm): These are duplicated from cookies_view_handler.cc
// Encodes a pointer value into a hex string.
std::string PointerToHexString(const void* pointer) {
@@ -52,11 +62,26 @@ std::string CertToId(const net::X509Certificate& cert) {
net::X509Certificate* IdToCert(const std::string& id) {
if (!StartsWithASCII(id, "cert-", true))
return NULL;
- return reinterpret_cast<net::X509Certificate*>(HexStringToPointer(id.substr(5)));
+ return reinterpret_cast<net::X509Certificate*>(
+ HexStringToPointer(id.substr(5)));
+}
+
+net::X509Certificate* CallbackArgsToCert(const ListValue* args) {
+ std::string node_id;
+ if (!args->GetString(0, &node_id)){
+ return NULL;
+ }
+ net::X509Certificate* cert = IdToCert(node_id);
+ if (!cert) {
+ NOTREACHED();
+ return NULL;
+ }
+ return cert;
}
struct DictionaryIdComparator {
- DictionaryIdComparator(icu::Collator* collator) : collator_(collator) {
+ explicit DictionaryIdComparator(icu::Collator* collator)
+ : collator_(collator) {
}
bool operator()(const Value* a,
@@ -80,8 +105,112 @@ struct DictionaryIdComparator {
} // namespace
-CertificateManagerHandler::CertificateManagerHandler() {
- certificate_manager_model_.reset(new CertificateManagerModel);
+///////////////////////////////////////////////////////////////////////////////
+// FileAccessProvider
+
+// TODO(mattm): Move to some shared location?
+class FileAccessProvider
+ : public base::RefCountedThreadSafe<FileAccessProvider>,
+ public CancelableRequestProvider {
+ public:
+ // Reports 0 on success or errno on failure, and the data of the file upon
+ // success.
+ // TODO(mattm): don't pass std::string by value.. could use RefCountedBytes
+ // but it's a vector. Maybe do the derive from CancelableRequest thing
+ // described in cancelable_request.h?
+ typedef Callback2<int, std::string>::Type ReadCallback;
+
+ // Reports 0 on success or errno on failure, and the number of bytes written,
+ // on success.
+ typedef Callback2<int, int>::Type WriteCallback;
+
+ Handle StartRead(const FilePath& path,
+ CancelableRequestConsumerBase* consumer,
+ ReadCallback* callback);
+ Handle StartWrite(const FilePath& path,
+ const std::string& data,
+ CancelableRequestConsumerBase* consumer,
+ WriteCallback* callback);
+
+ private:
+ void DoRead(scoped_refptr<CancelableRequest<ReadCallback> > request,
+ FilePath path);
+ void DoWrite(scoped_refptr<CancelableRequest<WriteCallback> > request,
+ FilePath path,
+ std::string data);
+};
+
+CancelableRequestProvider::Handle FileAccessProvider::StartRead(
+ const FilePath& path,
+ CancelableRequestConsumerBase* consumer,
+ FileAccessProvider::ReadCallback* callback) {
+ scoped_refptr<CancelableRequest<ReadCallback> > request(
+ new CancelableRequest<ReadCallback>(callback));
+ AddRequest(request, consumer);
+
+ // Send the parameters and the request to the file thread.
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(this, &FileAccessProvider::DoRead, request, path));
+
+ // The handle will have been set by AddRequest.
+ return request->handle();
+}
+
+CancelableRequestProvider::Handle FileAccessProvider::StartWrite(
+ const FilePath& path,
+ const std::string& data,
+ CancelableRequestConsumerBase* consumer,
+ WriteCallback* callback) {
+ scoped_refptr<CancelableRequest<WriteCallback> > request(
+ new CancelableRequest<WriteCallback>(callback));
+ AddRequest(request, consumer);
+
+ // Send the parameters and the request to the file thWrite.
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ this, &FileAccessProvider::DoWrite, request, path, data));
+
+ // The handle will have been set by AddRequest.
+ return request->handle();
+}
+
+void FileAccessProvider::DoRead(
+ scoped_refptr<CancelableRequest<ReadCallback> > request,
+ FilePath path) {
+ if (request->canceled())
+ return;
+
+ std::string data;
+ VLOG(1) << "DoRead starting read";
+ bool success = file_util::ReadFileToString(path, &data);
+ int saved_errno = success ? 0 : errno;
+ VLOG(1) << "DoRead done read: " << success << " " << data.size();
+ request->ForwardResult(ReadCallback::TupleType(saved_errno, data));
+}
+
+void FileAccessProvider::DoWrite(
+ scoped_refptr<CancelableRequest<WriteCallback> > request,
+ FilePath path,
+ std::string data) {
+ VLOG(1) << "DoWrite starting write";
+ int bytes_written = file_util::WriteFile(path, data.data(), data.size());
+ int saved_errno = bytes_written >= 0 ? 0 : errno;
+ VLOG(1) << "DoWrite done write " << bytes_written;
+
+ if (request->canceled())
+ return;
+
+ request->ForwardResult(WriteCallback::TupleType(saved_errno, bytes_written));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CertificateManagerHandler
+
+CertificateManagerHandler::CertificateManagerHandler()
+ : file_access_provider_(new FileAccessProvider) {
+ certificate_manager_model_.reset(new CertificateManagerModel(this));
}
CertificateManagerHandler::~CertificateManagerHandler() {
@@ -135,38 +264,319 @@ void CertificateManagerHandler::GetLocalizedValues(
// Buttons.
localized_strings->SetString("view_certificate",
l10n_util::GetStringUTF16(IDS_CERT_MANAGER_VIEW_CERT_BUTTON));
+ localized_strings->SetString("import_certificate",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_BUTTON));
+ localized_strings->SetString("export_certificate",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_BUTTON));
+ localized_strings->SetString("export_all_certificates",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_ALL_BUTTON));
+ localized_strings->SetString("edit_certificate",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_BUTTON));
+ localized_strings->SetString("delete_certificate",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_BUTTON));
+
+ // Certificate Delete overlay strings.
+ localized_strings->SetString("personalCertsTabDeleteConfirm",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_FORMAT));
+ localized_strings->SetString("personalCertsTabDeleteImpact",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_DESCRIPTION));
+ // For now, use the "unknown" strings for email certs too. Maybe we should
+ // just get rid of the email tab.
+ localized_strings->SetString("emailCertsTabDeleteConfirm",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_UNKNOWN_FORMAT));
+ localized_strings->SetString("emailCertsTabDeleteImpact", "");
+ localized_strings->SetString("serverCertsTabDeleteConfirm",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_FORMAT));
+ localized_strings->SetString("serverCertsTabDeleteImpact",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_DESCRIPTION));
+ localized_strings->SetString("caCertsTabDeleteConfirm",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_FORMAT));
+ localized_strings->SetString("caCertsTabDeleteImpact",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_DESCRIPTION));
+ localized_strings->SetString("unknownCertsTabDeleteConfirm",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_UNKNOWN_FORMAT));
+ localized_strings->SetString("unknownCertsTabDeleteImpact", "");
+
+ // Certificate Restore overlay strings.
+ localized_strings->SetString("certificateRestorePasswordDescription",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_RESTORE_PASSWORD_DESC));
+ localized_strings->SetString("certificatePasswordLabel",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PASSWORD_LABEL));
+
+ // Personal Certificate Export overlay strings.
+ localized_strings->SetString("certificateExportPasswordDescription",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_DESC));
+ localized_strings->SetString("certificateExportPasswordHelp",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_HELP));
+ localized_strings->SetString("certificateConfirmPasswordLabel",
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CONFIRM_PASSWORD_LABEL));
}
void CertificateManagerHandler::RegisterMessages() {
dom_ui_->RegisterMessageCallback("viewCertificate",
NewCallback(this, &CertificateManagerHandler::View));
+ dom_ui_->RegisterMessageCallback("editCaCertificate",
+ NewCallback(this, &CertificateManagerHandler::EditCA));
+
+ dom_ui_->RegisterMessageCallback("editServerCertificate",
+ NewCallback(this, &CertificateManagerHandler::EditServer));
+
+ dom_ui_->RegisterMessageCallback("cancelImportExportCertificate",
+ NewCallback(this, &CertificateManagerHandler::CancelImportExportProcess));
+
+ dom_ui_->RegisterMessageCallback("exportPersonalCertificate",
+ NewCallback(this, &CertificateManagerHandler::ExportPersonal));
+ dom_ui_->RegisterMessageCallback("exportAllPersonalCertificates",
+ NewCallback(this, &CertificateManagerHandler::ExportAllPersonal));
+ dom_ui_->RegisterMessageCallback("exportPersonalCertificatePasswordSelected",
+ NewCallback(this,
+ &CertificateManagerHandler::ExportPersonalPasswordSelected));
+
+ dom_ui_->RegisterMessageCallback("importPersonalCertificate",
+ NewCallback(this, &CertificateManagerHandler::StartImportPersonal));
+ dom_ui_->RegisterMessageCallback("importPersonalCertificatePasswordSelected",
+ NewCallback(this,
+ &CertificateManagerHandler::ImportPersonalPasswordSelected));
+
+ dom_ui_->RegisterMessageCallback("importCaCertificate",
+ NewCallback(this, &CertificateManagerHandler::ImportCA));
+
+ dom_ui_->RegisterMessageCallback("exportCertificate",
+ NewCallback(this, &CertificateManagerHandler::Export));
+
+ dom_ui_->RegisterMessageCallback("deleteCertificate",
+ NewCallback(this, &CertificateManagerHandler::Delete));
+
dom_ui_->RegisterMessageCallback("populateCertificateManager",
NewCallback(this, &CertificateManagerHandler::Populate));
}
+void CertificateManagerHandler::CertificatesRefreshed() {
+ 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);
+ VLOG(1) << "populating finished";
+}
+
+void CertificateManagerHandler::FileSelected(const FilePath& path, int index,
+ void* params) {
+ switch (reinterpret_cast<intptr_t>(params)) {
+ case EXPORT_PERSONAL_FILE_SELECTED:
+ ExportPersonalFileSelected(path);
+ break;
+ case IMPORT_PERSONAL_FILE_SELECTED:
+ ImportPersonalFileSelected(path);
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void CertificateManagerHandler::FileSelectionCanceled(void* params) {
+ switch (reinterpret_cast<intptr_t>(params)) {
+ case EXPORT_PERSONAL_FILE_SELECTED:
+ case IMPORT_PERSONAL_FILE_SELECTED:
+ ImportExportCleanup();
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
void CertificateManagerHandler::View(const ListValue* args) {
- std::string node_id;
- if (!args->GetString(0, &node_id)){
+ net::X509Certificate* cert = CallbackArgsToCert(args);
+ if (!cert)
+ return;
+ ShowCertificateViewer(GetParentWindow(), cert);
+}
+
+void CertificateManagerHandler::EditCA(const ListValue* args) {
+ NOTIMPLEMENTED();
+}
+
+void CertificateManagerHandler::EditServer(const ListValue* args) {
+ NOTIMPLEMENTED();
+}
+
+void CertificateManagerHandler::ExportPersonal(const ListValue* args) {
+ net::X509Certificate* cert = CallbackArgsToCert(args);
+ if (!cert)
+ return;
+
+ selected_cert_list_.push_back(cert);
+
+ SelectFileDialog::FileTypeInfo file_type_info;
+ file_type_info.extensions.resize(1);
+ file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12"));
+ file_type_info.extension_description_overrides.push_back(
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES));
+ file_type_info.include_all_files = true;
+ select_file_dialog_ = SelectFileDialog::Create(this);
+ select_file_dialog_->SelectFile(
+ SelectFileDialog::SELECT_SAVEAS_FILE, string16(),
+ FilePath(), &file_type_info, 1,
+ FILE_PATH_LITERAL("p12"), GetParentWindow(),
+ reinterpret_cast<void*>(EXPORT_PERSONAL_FILE_SELECTED));
+}
+
+void CertificateManagerHandler::ExportAllPersonal(const ListValue* args) {
+ NOTIMPLEMENTED();
+}
+
+void CertificateManagerHandler::ExportPersonalFileSelected(
+ const FilePath& path) {
+ file_path_ = path;
+ dom_ui_->CallJavascriptFunction(
+ L"CertificateManager.exportPersonalAskPassword");
+}
+
+void CertificateManagerHandler::ExportPersonalPasswordSelected(
+ const ListValue* args) {
+ if (!args->GetString(0, &password_)){
+ dom_ui_->CallJavascriptFunction(L"CertificateRestoreOverlay.dismiss");
+ ImportExportCleanup();
return;
}
- net::X509Certificate* cert = IdToCert(node_id);
- if (!cert) {
- NOTREACHED();
+ std::string output;
+ int num_exported = certificate_manager_model_->ExportToPKCS12(
+ selected_cert_list_,
+ password_,
+ &output);
+ if (!num_exported) {
+ ShowError(
+ l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
+ l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
+ dom_ui_->CallJavascriptFunction(L"CertificateRestoreOverlay.dismiss");
+ ImportExportCleanup();
+ return;
+ }
+ file_access_provider_->StartWrite(
+ file_path_,
+ output,
+ &consumer_,
+ NewCallback(this, &CertificateManagerHandler::ExportPersonalFileWritten));
+}
+
+void CertificateManagerHandler::ExportPersonalFileWritten(int write_errno,
+ int bytes_written) {
+ dom_ui_->CallJavascriptFunction(L"CertificateRestoreOverlay.dismiss");
+ ImportExportCleanup();
+ if (write_errno) {
+ ShowError(
+ l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
+ l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_WRITE_ERROR_FORMAT,
+ UTF8ToUTF16(safe_strerror(write_errno))));
+ }
+}
+
+void CertificateManagerHandler::StartImportPersonal(const ListValue* args) {
+ SelectFileDialog::FileTypeInfo file_type_info;
+ file_type_info.extensions.resize(1);
+ file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12"));
+ file_type_info.extension_description_overrides.push_back(
+ l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES));
+ file_type_info.include_all_files = true;
+ select_file_dialog_ = SelectFileDialog::Create(this);
+ select_file_dialog_->SelectFile(
+ SelectFileDialog::SELECT_OPEN_FILE, string16(),
+ FilePath(), &file_type_info, 1,
+ FILE_PATH_LITERAL("p12"), GetParentWindow(),
+ reinterpret_cast<void*>(IMPORT_PERSONAL_FILE_SELECTED));
+}
+
+void CertificateManagerHandler::ImportPersonalFileSelected(
+ const FilePath& path) {
+ file_path_ = path;
+ dom_ui_->CallJavascriptFunction(
+ L"CertificateManager.importPersonalAskPassword");
+}
+
+void CertificateManagerHandler::ImportPersonalPasswordSelected(
+ const ListValue* args) {
+ if (!args->GetString(0, &password_)){
+ dom_ui_->CallJavascriptFunction(L"CertificateRestoreOverlay.dismiss");
+ ImportExportCleanup();
+ return;
+ }
+ file_access_provider_->StartRead(
+ file_path_,
+ &consumer_,
+ NewCallback(this, &CertificateManagerHandler::ImportPersonalFileRead));
+}
+
+void CertificateManagerHandler::ImportPersonalFileRead(
+ int read_errno, std::string data) {
+ if (read_errno) {
+ ImportExportCleanup();
+ dom_ui_->CallJavascriptFunction(L"CertificateRestoreOverlay.dismiss");
+ ShowError(
+ l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
+ l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
+ UTF8ToUTF16(safe_strerror(read_errno))));
return;
}
- ShowCertificateViewer(
- dom_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), cert);
+ int result = certificate_manager_model_->ImportFromPKCS12(data, password_);
+ ImportExportCleanup();
+ dom_ui_->CallJavascriptFunction(L"CertificateRestoreOverlay.dismiss");
+ switch (result) {
+ case net::OK:
+ break;
+ case net::ERR_PKCS12_IMPORT_BAD_PASSWORD:
+ ShowError(
+ l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
+ l10n_util::GetStringUTF8(IDS_CERT_MANAGER_BAD_PASSWORD));
+ // TODO(mattm): if the error was a bad password, we should reshow the
+ // password dialog after the user dismisses the error dialog.
+ break;
+ default:
+ ShowError(
+ l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
+ l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
+ break;
+ }
+}
+
+void CertificateManagerHandler::CancelImportExportProcess(
+ const ListValue* args) {
+ ImportExportCleanup();
+}
+
+void CertificateManagerHandler::ImportExportCleanup() {
+ file_path_.clear();
+ password_.clear();
+ selected_cert_list_.clear();
+ select_file_dialog_ = NULL;
+}
+
+void CertificateManagerHandler::ImportCA(const ListValue* args) {
+ NOTIMPLEMENTED();
+}
+
+void CertificateManagerHandler::Export(const ListValue* args) {
+ net::X509Certificate* cert = CallbackArgsToCert(args);
+ if (!cert)
+ return;
+ ShowCertExportDialog(GetParentWindow(), cert->os_cert_handle());
+}
+
+void CertificateManagerHandler::Delete(const ListValue* args) {
+ net::X509Certificate* cert = CallbackArgsToCert(args);
+ if (!cert)
+ return;
+ bool result = certificate_manager_model_->Delete(cert);
+ if (!result) {
+ // TODO(mattm): better error messages?
+ ShowError(
+ l10n_util::GetStringUTF8(IDS_CERT_MANAGER_DELETE_CERT_ERROR_TITLE),
+ l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
+ }
}
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,
@@ -223,3 +633,19 @@ void CertificateManagerHandler::PopulateTree(const std::string& tab_name,
dom_ui_->CallJavascriptFunction(L"CertificateManager.onPopulateTree", args);
}
}
+
+void CertificateManagerHandler::ShowError(const std::string& title,
+ const std::string& error) const {
+ std::vector<const Value*> args;
+ args.push_back(Value::CreateStringValue(title));
+ args.push_back(Value::CreateStringValue(error));
+ args.push_back(Value::CreateNullValue()); // okTitle
+ args.push_back(Value::CreateStringValue("")); // cancelTitle
+ args.push_back(Value::CreateNullValue()); // okCallback
+ args.push_back(Value::CreateNullValue()); // cancelCallback
+ dom_ui_->CallJavascriptFunction(L"AlertOverlay.show", args);
+}
+
+gfx::NativeWindow CertificateManagerHandler::GetParentWindow() const {
+ return dom_ui_->tab_contents()->view()->GetTopLevelNativeWindow();
+}
diff --git a/chrome/browser/dom_ui/options/certificate_manager_handler.h b/chrome/browser/dom_ui/options/certificate_manager_handler.h
index 3766b57..48534f5 100644
--- a/chrome/browser/dom_ui/options/certificate_manager_handler.h
+++ b/chrome/browser/dom_ui/options/certificate_manager_handler.h
@@ -7,12 +7,18 @@
#pragma once
#include "base/scoped_ptr.h"
+#include "chrome/browser/cancelable_request.h"
+#include "chrome/browser/certificate_manager_model.h"
#include "chrome/browser/dom_ui/options/options_ui.h"
+#include "chrome/browser/shell_dialogs.h"
+#include "gfx/native_widget_types.h"
#include "net/base/cert_database.h"
-class CertificateManagerModel;
+class FileAccessProvider;
-class CertificateManagerHandler : public OptionsPageUIHandler {
+class CertificateManagerHandler : public OptionsPageUIHandler,
+ public CertificateManagerModel::Observer,
+ public SelectFileDialog::Listener {
public:
CertificateManagerHandler();
virtual ~CertificateManagerHandler();
@@ -21,19 +27,94 @@ class CertificateManagerHandler : public OptionsPageUIHandler {
virtual void GetLocalizedValues(DictionaryValue* localized_strings);
virtual void RegisterMessages();
+ // CertificateManagerModel::Observer implementation.
+ virtual void CertificatesRefreshed();
+
+ // SelectFileDialog::Listener implementation.
+ virtual void FileSelected(const FilePath& path, int index, void* params);
+ virtual void FileSelectionCanceled(void* params);
+
private:
// View certificate.
void View(const ListValue* args);
+ // Edit server certificate trust values.
+ void EditServer(const ListValue* args);
+
+ // Edit certificate authority trust values.
+ void EditCA(const ListValue* args);
+
+ // Cleanup state stored during import or export process.
+ void CancelImportExportProcess(const ListValue* args);
+ void ImportExportCleanup();
+
+ // Export to PKCS #12 file. The sequence goes like:
+ // 1a. user click on export button -> ExportPersonal -> launches file
+ // selector
+ // 1b. user click on export all button -> ExportAllPersonal -> launches file
+ // selector
+ // 2. user selects file -> ExportPersonalFileSelected -> launches password
+ // dialog
+ // 3. user enters password -> ExportPersonalPasswordSelected -> exports to
+ // memory buffer -> starts async write operation
+ // 4. write finishes (or fails) -> ExportPersonalFileWritten
+ void ExportPersonal(const ListValue* args);
+ void ExportAllPersonal(const ListValue* args);
+ void ExportPersonalFileSelected(const FilePath& path);
+ void ExportPersonalPasswordSelected(const ListValue* args);
+ void ExportPersonalFileWritten(int write_errno, int bytes_written);
+
+ // Import from PKCS #12 file. The sequence goes like:
+ // 1. user click on import button -> StartImportPersonal -> launches file
+ // selector
+ // 2. user selects file -> ImportPersonalFileSelected -> launches password
+ // dialog
+ // 3. user enters password -> ImportPersonalPasswordSelected -> starts async
+ // read operation
+ // 4. read operation completes -> ImportPersonalFileRead -> attempts to
+ // import with previously entered password
+ // 5a. if import succeeds -> ImportExportCleanup
+ // 5b. if import fails -> show error, ImportExportCleanup
+ // TODO(mattm): allow retrying with different password
+ void StartImportPersonal(const ListValue* args);
+ void ImportPersonalFileSelected(const FilePath& path);
+ void ImportPersonalPasswordSelected(const ListValue* args);
+ void ImportPersonalFileRead(int read_errno, std::string data);
+
+ void ImportCA(const ListValue* args);
+
+ // Export a certificate.
+ void Export(const ListValue* args);
+
+ // Delete certificate and private key (if any).
+ void Delete(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);
+ // Display a domui error message box.
+ void ShowError(const std::string& title, const std::string& error) const;
+
+ gfx::NativeWindow GetParentWindow() const;
+
// The Certificates Manager model
scoped_ptr<CertificateManagerModel> certificate_manager_model_;
+ // For multi-step import or export processes, we need to store the path,
+ // password, etc the user chose while we wait for them to enter a password,
+ // wait for file to be read, etc.
+ FilePath file_path_;
+ string16 password_;
+ net::CertificateList selected_cert_list_;
+ scoped_refptr<SelectFileDialog> select_file_dialog_;
+
+ // Used in reading and writing certificate files.
+ CancelableRequestConsumer consumer_;
+ scoped_refptr<FileAccessProvider> file_access_provider_;
+
DISALLOW_COPY_AND_ASSIGN(CertificateManagerHandler);
};
diff --git a/chrome/browser/gtk/certificate_dialogs.cc b/chrome/browser/gtk/certificate_dialogs.cc
index ba12f6d..a42a1ad 100644
--- a/chrome/browser/gtk/certificate_dialogs.cc
+++ b/chrome/browser/gtk/certificate_dialogs.cc
@@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// TODO(mattm): this isn't gtk specific, it shouldn't be under the gtk dir
+
+// TODO(mattm): the nss export functions should be moved to cert_database_nss or
+// x509_certificate_nss.
+
#include "chrome/browser/gtk/certificate_dialogs.h"
#include <cms.h>
-#include <gtk/gtk.h>
#include <vector>
diff --git a/chrome/browser/resources/options.html b/chrome/browser/resources/options.html
index 686a17c..15aac2c 100644
--- a/chrome/browser/resources/options.html
+++ b/chrome/browser/resources/options.html
@@ -82,8 +82,12 @@
<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 src="options/certificate_restore_overlay.js"></script>
+ <script src="options/certificate_backup_overlay.js"></script>
<script>
var CertificateManager = options.CertificateManager;
+ var CertificateRestoreOverlay = options.CertificateRestoreOverlay;
+ var CertificateBackupOverlay = options.CertificateBackupOverlay;
</script>
</if>
<script src="options/add_startup_page_overlay.js"></script>
@@ -163,6 +167,8 @@ function load() {
OptionsPage.registerSubPage(SyncOptions.getInstance());
if (!cr.isWindows && !cr.isMac) {
OptionsPage.registerSubPage(CertificateManager.getInstance());
+ OptionsPage.registerOverlay(CertificateRestoreOverlay.getInstance());
+ OptionsPage.registerOverlay(CertificateBackupOverlay.getInstance());
}
OptionsPage.registerOverlay(AddStartupPageOverlay.getInstance());
OptionsPage.registerOverlay(AlertOverlay.getInstance());
@@ -269,6 +275,10 @@ window.onpopstate = function(e) {
src="options/chromeos_language_customize_modifier_keys_overlay.html">
<include src="options/chromeos_internet_detail.html">
</if>
+ <if expr="not pp_ifdef('win32') and not pp_ifdef('darwin')">
+ <include src="options/certificate_restore_overlay.html">
+ <include src="options/certificate_backup_overlay.html">
+ </if>
</div>
<div id="main-content">
<div id="navbar-container">
diff --git a/chrome/browser/resources/options/certificate_backup_overlay.html b/chrome/browser/resources/options/certificate_backup_overlay.html
new file mode 100644
index 0000000..0565e05
--- /dev/null
+++ b/chrome/browser/resources/options/certificate_backup_overlay.html
@@ -0,0 +1,42 @@
+<div class="page hidden" id="certificateBackupOverlay">
+ <p>
+ <span i18n-content="certificateExportPasswordDescription"></span>
+ </p>
+
+ <p>
+ <table>
+ <tr>
+ <label id="certificateBackupPasswordLabel">
+ <td>
+ <span i18n-content="certificatePasswordLabel"></span>
+ </td>
+ <td>
+ <input type="password" id="certificateBackupPassword">
+ </td>
+ </label>
+ </tr>
+ <tr>
+ <label id="certificateBackupPasswordLabel">
+ <td>
+ <span i18n-content="certificateConfirmPasswordLabel"></span>
+ </td>
+ <td>
+ <input type="password" id="certificateBackupPassword2">
+ </td>
+ </label>
+ </tr>
+ </table>
+ </p>
+
+ <p>
+ <span i18n-content="certificateExportPasswordHelp"></span>
+ </p>
+
+ <div class="button-strip">
+ <button type="submit" id="certificateBackupOkButton"
+ i18n-content="ok" disabled></button>
+ <button type="reset" id="certificateBackupCancelButton"
+ i18n-content="cancel"></button>
+ </div>
+</div>
+
diff --git a/chrome/browser/resources/options/certificate_backup_overlay.js b/chrome/browser/resources/options/certificate_backup_overlay.js
new file mode 100644
index 0000000..f5da035
--- /dev/null
+++ b/chrome/browser/resources/options/certificate_backup_overlay.js
@@ -0,0 +1,118 @@
+// 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 OptionsPage = options.OptionsPage;
+
+ /**
+ * CertificateBackupOverlay class
+ * Encapsulated handling of the 'enter backup password' overlay page.
+ * @class
+ */
+ function CertificateBackupOverlay() {
+ OptionsPage.call(this, 'certificateBackupOverlay',
+ '',
+ 'certificateBackupOverlay');
+ }
+
+ cr.addSingletonGetter(CertificateBackupOverlay);
+
+ CertificateBackupOverlay.prototype = {
+ __proto__: OptionsPage.prototype,
+
+ /**
+ * Initializes the page.
+ */
+ initializePage: function() {
+ OptionsPage.prototype.initializePage.call(this);
+
+ var self = this;
+ $('certificateBackupCancelButton').onclick = function(event) {
+ self.cancelBackup_();
+ }
+ $('certificateBackupOkButton').onclick = function(event) {
+ self.finishBackup_();
+ }
+ $('certificateBackupPassword').oninput =
+ $('certificateBackupPassword2').oninput = function(event) {
+ self.comparePasswords_();
+ }
+
+ self.clearInputFields_();
+ },
+
+ /**
+ * Clears any uncommitted input, and dismisses the overlay.
+ * @private
+ */
+ dismissOverlay_: function() {
+ this.clearInputFields_();
+ OptionsPage.clearOverlays();
+ },
+
+ /**
+ * Attempt the Backup operation.
+ * The overlay will be left up with inputs disabled until the backend
+ * finishes and dismisses it.
+ * @private
+ */
+ finishBackup_: function() {
+ chrome.send('exportPersonalCertificatePasswordSelected',
+ [$('certificateBackupPassword').value]);
+ $('certificateBackupCancelButton').disabled = true;
+ $('certificateBackupOkButton').disabled = true;
+ $('certificateBackupPassword').disabled = true;
+ $('certificateBackupPassword2').disabled = true;
+ },
+
+ /**
+ * Cancel the Backup operation.
+ * @private
+ */
+ cancelBackup_: function() {
+ chrome.send('cancelImportExportCertificate');
+ this.dismissOverlay_();
+ },
+
+ /**
+ * Compares the password fields and sets the button state appropriately.
+ * @private
+ */
+ comparePasswords_: function() {
+ var password1 = $('certificateBackupPassword').value;
+ var password2 = $('certificateBackupPassword2').value;
+ $('certificateBackupOkButton').disabled =
+ !password1 || password1 != password2;
+ },
+
+ /**
+ * Clears the value of each input field.
+ * @private
+ */
+ clearInputFields_: function() {
+ $('certificateBackupPassword').value = '';
+ $('certificateBackupPassword2').value = '';
+ $('certificateBackupPassword').disabled = false;
+ $('certificateBackupPassword2').disabled = false;
+ $('certificateBackupCancelButton').disabled = false;
+ $('certificateBackupOkButton').disabled = true;
+ },
+ };
+
+ CertificateBackupOverlay.show = function() {
+ CertificateBackupOverlay.getInstance().clearInputFields_();
+ OptionsPage.showOverlay('certificateBackupOverlay');
+ };
+
+ CertificateBackupOverlay.dismiss = function() {
+ CertificateBackupOverlay.getInstance().dismissOverlay_();
+ };
+
+ // Export
+ return {
+ CertificateBackupOverlay: CertificateBackupOverlay
+ };
+
+});
+
diff --git a/chrome/browser/resources/options/certificate_manager.html b/chrome/browser/resources/options/certificate_manager.html
index 32821f2..14b0feb 100644
--- a/chrome/browser/resources/options/certificate_manager.html
+++ b/chrome/browser/resources/options/certificate_manager.html
@@ -33,7 +33,17 @@
<tr><td>
<button id="personalCertsTab-view" i18n-content="view_certificate"
disabled></button>
- <!-- TODO other buttons -->
+ <button id="personalCertsTab-backup" i18n-content="export_certificate"
+ disabled></button>
+ <!-- TODO(mattm):
+ <button id="personalCertsTab-backup-all"
+ i18n-content="export_all_certificates"
+ disabled></button>
+ -->
+ <button id="personalCertsTab-import" i18n-content="import_certificate"
+ ></button>
+ <button id="personalCertsTab-delete" i18n-content="delete_certificate"
+ disabled></button>
</td></tr>
</table>
</div>
@@ -49,7 +59,17 @@
<tr><td>
<button id="emailCertsTab-view" i18n-content="view_certificate"
disabled></button>
- <!-- TODO other buttons -->
+ <!-- We don't really care about email certificates, so not much point
+ bothering to implement these...
+ <button id="emailCertsTab-edit" i18n-content="edit_certificate"
+ disabled></button>
+ <button id="emailCertsTab-import" i18n-content="import_certificate"
+ ></button>
+ -->
+ <button id="emailCertsTab-export" i18n-content="export_certificate"
+ disabled></button>
+ <button id="emailCertsTab-delete" i18n-content="delete_certificate"
+ disabled></button>
</td></tr>
</table>
</div>
@@ -65,7 +85,16 @@
<tr><td>
<button id="serverCertsTab-view" i18n-content="view_certificate"
disabled></button>
- <!-- TODO other buttons -->
+ <!-- TODO(mattm):
+ <button id="serverCertsTab-edit" i18n-content="edit_certificate"
+ disabled></button>
+ <button id="serverCertsTab-import" i18n-content="import_certificate"
+ ></button>
+ -->
+ <button id="serverCertsTab-export" i18n-content="export_certificate"
+ disabled></button>
+ <button id="serverCertsTab-delete" i18n-content="delete_certificate"
+ disabled></button>
</td></tr>
</table>
</div>
@@ -81,7 +110,16 @@
<tr><td>
<button id="caCertsTab-view" i18n-content="view_certificate"
disabled></button>
- <!-- TODO other buttons -->
+ <!-- TODO(mattm):
+ <button id="caCertsTab-edit" i18n-content="edit_certificate"
+ disabled></button>
+ <button id="caCertsTab-import" i18n-content="import_certificate"
+ ></button>
+ -->
+ <button id="caCertsTab-export" i18n-content="export_certificate"
+ disabled></button>
+ <button id="caCertsTab-delete" i18n-content="delete_certificate"
+ disabled></button>
</td></tr>
</table>
</div>
@@ -97,7 +135,10 @@
<tr><td>
<button id="otherCertsTab-view" i18n-content="view_certificate"
disabled></button>
- <!-- TODO other buttons -->
+ <button id="otherCertsTab-export" i18n-content="export_certificate"
+ disabled></button>
+ <button id="otherCertsTab-delete" i18n-content="delete_certificate"
+ disabled></button>
</td></tr>
</table>
</div>
diff --git a/chrome/browser/resources/options/certificate_manager.js b/chrome/browser/resources/options/certificate_manager.js
index 741809e..9bcba83 100644
--- a/chrome/browser/resources/options/certificate_manager.js
+++ b/chrome/browser/resources/options/certificate_manager.js
@@ -20,14 +20,80 @@ cr.define('options', function() {
this.tree.addEventListener('change',
this.handleCertificatesTreeChange_.bind(this));
+ var tree = this.tree;
this.viewButton = $(id + '-view');
-
- var tree = this.tree;
this.viewButton.onclick = function(e) {
var selected = tree.selectedItem;
chrome.send('viewCertificate', [selected.data.id]);
}
+
+ this.editButton = $(id + '-edit');
+ if (this.editButton !== null) {
+ if (id == 'serverCertsTab') {
+ this.editButton.onclick = function(e) {
+ var selected = tree.selectedItem;
+ chrome.send('editServerCertificate', [selected.data.id]);
+ }
+ } else if (id == 'caCertsTab') {
+ this.editButton.onclick = function(e) {
+ var selected = tree.selectedItem;
+ chrome.send('editCaCertificate', [selected.data.id]);
+ }
+ } else {
+ console.log('unknown edit button for: ' + id);
+ }
+ }
+
+ this.backupButton = $(id + '-backup');
+ if (this.backupButton !== null) {
+ this.backupButton.onclick = function(e) {
+ var selected = tree.selectedItem;
+ chrome.send('exportPersonalCertificate', [selected.data.id]);
+ }
+ }
+
+ this.backupAllButton = $(id + '-backup-all');
+ if (this.backupAllButton !== null) {
+ this.backupAllButton.onclick = function(e) {
+ chrome.send('exportAllPersonalCertificates', []);
+ }
+ }
+
+ this.importButton = $(id + '-import');
+ if (this.importButton !== null) {
+ if (id == 'personalCertsTab') {
+ this.importButton.onclick = function(e) {
+ chrome.send('importPersonalCertificate', []);
+ }
+ } else if (id == 'caCertsTab') {
+ this.importButton.onclick = function(e) {
+ chrome.send('importCaCertificate', []);
+ }
+ } else {
+ console.log('unknown import button for: ' + id);
+ }
+ }
+
+ this.exportButton = $(id + '-export');
+ if (this.exportButton !== null) {
+ this.exportButton.onclick = function(e) {
+ var selected = tree.selectedItem;
+ chrome.send('exportCertificate', [selected.data.id]);
+ }
+ }
+
+ this.deleteButton = $(id + '-delete');
+ this.deleteButton.onclick = function(e) {
+ var data = tree.selectedItem.data;
+ AlertOverlay.show(
+ localStrings.getStringF(id + 'DeleteConfirm', data.name),
+ localStrings.getString(id + 'DeleteImpact'),
+ undefined,
+ undefined,
+ function() { chrome.send('deleteCertificate', [data.id]); }
+ );
+ }
}
CertificateManagerTab.prototype = {
@@ -39,7 +105,17 @@ cr.define('options', function() {
*/
updateButtonState: function(data) {
var isCert = !!data && data.id.substr(0, 5) == 'cert-';
+ var hasChildren = this.tree.items.length > 0;
this.viewButton.disabled = !isCert;
+ if (this.editButton !== null)
+ this.editButton.disabled = !isCert;
+ if (this.backupButton !== null)
+ this.backupButton.disabled = !isCert;
+ if (this.backupAllButton !== null)
+ this.backupAllButton.disabled = !hasChildren;
+ if (this.exportButton !== null)
+ this.exportButton.disabled = !isCert;
+ this.deleteButton.disabled = !isCert;
},
/**
@@ -108,6 +184,14 @@ cr.define('options', function() {
$(args[0]).populate(args[1]);
};
+ CertificateManager.exportPersonalAskPassword = function(args) {
+ CertificateBackupOverlay.show();
+ };
+
+ CertificateManager.importPersonalAskPassword = function(args) {
+ CertificateRestoreOverlay.show();
+ };
+
// Export
return {
CertificateManagerTab: CertificateManagerTab,
diff --git a/chrome/browser/resources/options/certificate_restore_overlay.html b/chrome/browser/resources/options/certificate_restore_overlay.html
new file mode 100644
index 0000000..7985ff2
--- /dev/null
+++ b/chrome/browser/resources/options/certificate_restore_overlay.html
@@ -0,0 +1,19 @@
+<div class="page hidden" id="certificateRestoreOverlay">
+ <p>
+ <span i18n-content="certificateRestorePasswordDescription"></span>
+ </p>
+
+ <p>
+ <label id="certificateRestorePasswordLabel">
+ <span i18n-content="certificatePasswordLabel"></span>
+ <input type="password" id="certificateRestorePassword">
+ </label>
+ </p>
+
+ <div class="button-strip">
+ <button type="submit" id="certificateRestoreOkButton"
+ i18n-content="ok"></button>
+ <button type="reset" id="certificateRestoreCancelButton"
+ i18n-content="cancel"></button>
+ </div>
+</div>
diff --git a/chrome/browser/resources/options/certificate_restore_overlay.js b/chrome/browser/resources/options/certificate_restore_overlay.js
new file mode 100644
index 0000000..2673c08
--- /dev/null
+++ b/chrome/browser/resources/options/certificate_restore_overlay.js
@@ -0,0 +1,97 @@
+// 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 OptionsPage = options.OptionsPage;
+
+ /**
+ * CertificateRestoreOverlay class
+ * Encapsulated handling of the 'enter restore password' overlay page.
+ * @class
+ */
+ function CertificateRestoreOverlay() {
+ OptionsPage.call(this, 'certificateRestoreOverlay',
+ '',
+ 'certificateRestoreOverlay');
+ }
+
+ cr.addSingletonGetter(CertificateRestoreOverlay);
+
+ CertificateRestoreOverlay.prototype = {
+ __proto__: OptionsPage.prototype,
+
+ /**
+ * Initializes the page.
+ */
+ initializePage: function() {
+ OptionsPage.prototype.initializePage.call(this);
+
+ var self = this;
+ $('certificateRestoreCancelButton').onclick = function(event) {
+ self.cancelRestore_();
+ }
+ $('certificateRestoreOkButton').onclick = function(event) {
+ self.finishRestore_();
+ }
+
+ self.clearInputFields_();
+ },
+
+ /**
+ * Clears any uncommitted input, and dismisses the overlay.
+ * @private
+ */
+ dismissOverlay_: function() {
+ this.clearInputFields_();
+ OptionsPage.clearOverlays();
+ },
+
+ /**
+ * Attempt the restore operation.
+ * The overlay will be left up with inputs disabled until the backend
+ * finishes and dismisses it.
+ * @private
+ */
+ finishRestore_: function() {
+ chrome.send('importPersonalCertificatePasswordSelected',
+ [$('certificateRestorePassword').value]);
+ $('certificateRestoreCancelButton').disabled = true;
+ $('certificateRestoreOkButton').disabled = true;
+ },
+
+ /**
+ * Cancel the restore operation.
+ * @private
+ */
+ cancelRestore_: function() {
+ chrome.send('cancelImportExportCertificate');
+ this.dismissOverlay_();
+ },
+
+ /**
+ * Clears the value of each input field.
+ * @private
+ */
+ clearInputFields_: function() {
+ $('certificateRestorePassword').value = '';
+ $('certificateRestoreCancelButton').disabled = false;
+ $('certificateRestoreOkButton').disabled = false;
+ },
+ };
+
+ CertificateRestoreOverlay.show = function() {
+ CertificateRestoreOverlay.getInstance().clearInputFields_();
+ OptionsPage.showOverlay('certificateRestoreOverlay');
+ };
+
+ CertificateRestoreOverlay.dismiss = function() {
+ CertificateRestoreOverlay.getInstance().dismissOverlay_();
+ };
+
+ // Export
+ return {
+ CertificateRestoreOverlay: CertificateRestoreOverlay
+ };
+
+});