#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/browser.h"
+#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "brightray/browser/brightray_paths.h"
+#include "content/public/browser/client_certificate_delegate.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
+#include "net/ssl/ssl_cert_request_info.h"
#if defined(OS_WIN)
#include "base/strings/utf_string_conversions.h"
};
#endif
+template<>
+struct Converter<scoped_refptr<net::X509Certificate>> {
+ static v8::Local<v8::Value> ToV8(
+ v8::Isolate* isolate,
+ const scoped_refptr<net::X509Certificate>& val) {
+ mate::Dictionary dict(isolate, v8::Object::New(isolate));
+ std::string encoded_data;
+ net::X509Certificate::GetPEMEncoded(
+ val->os_cert_handle(), &encoded_data);
+ dict.Set("data", encoded_data);
+ dict.Set("issuerName", val->issuer().GetDisplayName());
+ return dict.GetHandle();
+ }
+};
+
} // namespace mate
return -1;
}
+void OnClientCertificateSelected(
+ v8::Isolate* isolate,
+ std::shared_ptr<content::ClientCertificateDelegate> delegate,
+ mate::Arguments* args) {
+ v8::Locker locker(isolate);
+ v8::HandleScope handle_scope(isolate);
+ mate::Dictionary cert_data;
+ if (!(args->Length() == 1 && args->GetNext(&cert_data))) {
+ args->ThrowError();
+ return;
+ }
+
+ std::string encoded_data;
+ cert_data.Get("data", &encoded_data);
+
+ auto certs =
+ net::X509Certificate::CreateCertificateListFromBytes(
+ encoded_data.data(), encoded_data.size(),
+ net::X509Certificate::FORMAT_AUTO);
+
+ delegate->ContinueWithCertificate(certs[0].get());
+}
+
} // namespace
App::App() {
Emit("ready");
}
+void App::OnSelectCertificate(
+ content::WebContents* web_contents,
+ net::SSLCertRequestInfo* cert_request_info,
+ scoped_ptr<content::ClientCertificateDelegate> delegate) {
+ std::shared_ptr<content::ClientCertificateDelegate>
+ shared_delegate(delegate.release());
+ bool prevent_default =
+ Emit("select-certificate",
+ api::WebContents::CreateFrom(isolate(), web_contents),
+ cert_request_info->host_and_port.ToString(),
+ cert_request_info->client_certs,
+ base::Bind(&OnClientCertificateSelected,
+ isolate(),
+ shared_delegate));
+
+ // Default to first certificate from the platform store.
+ if (!prevent_default)
+ shared_delegate->ContinueWithCertificate(
+ cert_request_info->client_certs[0].get());
+}
+
base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) {
bool succeed = false;
base::FilePath path;
void OnActivateWithNoOpenWindows() override;
void OnWillFinishLaunching() override;
void OnFinishLaunching() override;
+ void OnSelectCertificate(
+ content::WebContents* web_contents,
+ net::SSLCertRequestInfo* cert_request_info,
+ scoped_ptr<content::ClientCertificateDelegate> delegate) override;
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_quota_permission_context.h"
#include "atom/browser/atom_speech_recognition_manager_delegate.h"
+#include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
#include "atom/browser/web_view_manager.h"
#include "atom/browser/window_list.h"
auto cert_path = command_line->GetSwitchValueNative(
switches::kClientCertificate);
- // TODO(zcbenz): allow users to select certificate from
- // client_cert list. Right now defaults to first certificate
- // in the list.
scoped_refptr<net::X509Certificate> certificate;
- if (cert_path.empty()) {
- if (!cert_request_info->client_certs.empty())
- certificate = cert_request_info->client_certs[0];
- } else {
+ if (!cert_path.empty()) {
certificate = ImportCertFromFile(base::FilePath(cert_path));
+ } else if (!cert_request_info->client_certs.empty()) {
+ Browser::Get()->ClientCertificateSelector(web_contents,
+ cert_request_info,
+ delegate.Pass());
}
if (certificate.get())
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/window_list.h"
#include "base/message_loop/message_loop.h"
+#include "content/public/browser/client_certificate_delegate.h"
+#include "net/ssl/ssl_cert_request_info.h"
namespace atom {
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching());
}
+void Browser::ClientCertificateSelector(
+ content::WebContents* web_contents,
+ net::SSLCertRequestInfo* cert_request_info,
+ scoped_ptr<content::ClientCertificateDelegate> delegate) {
+ FOR_EACH_OBSERVER(BrowserObserver,
+ observers_,
+ OnSelectCertificate(web_contents,
+ cert_request_info,
+ delegate.Pass()));
+}
+
void Browser::NotifyAndShutdown() {
bool prevent_default = false;
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default));
void WillFinishLaunching();
void DidFinishLaunching();
+ // Called when client certificate is required.
+ void ClientCertificateSelector(
+ content::WebContents* web_contents,
+ net::SSLCertRequestInfo* cert_request_info,
+ scoped_ptr<content::ClientCertificateDelegate> delegate);
+
void AddObserver(BrowserObserver* obs) {
observers_.AddObserver(obs);
}
#include <string>
+#include "base/memory/scoped_ptr.h"
+
+namespace content {
+class ClientCertificateDelegate;
+class WebContents;
+}
+
+namespace net {
+class SSLCertRequestInfo;
+}
+
namespace atom {
class BrowserObserver {
virtual void OnWillFinishLaunching() {}
virtual void OnFinishLaunching() {}
+ // The browser requires client certificate.
+ virtual void OnSelectCertificate(
+ content::WebContents* web_contents,
+ net::SSLCertRequestInfo* cert_request_info,
+ scoped_ptr<content::ClientCertificateDelegate> delegate) {}
+
protected:
virtual ~BrowserObserver() {}
};
Emitted when a [browserWindow](browser-window.md) gets focused.
+### Event: 'select-certificate'
+
+Emitted when client certificate is requested.
+
+* `event` Event
+* `webContents` [WebContents](browser-window.md#class-webcontents)
+* `url` String
+* `certificateList` [Objects]
+ * `data` PEM encoded data
+ * `issuerName` Issuer's Common Name
+* `callback` Function
+
+```
+app.on('select-certificate', function(event, host, url, list, callback) {
+ event.preventDefault();
+ callback(list[0]);
+})
+```
+
+`url` corresponds to the navigation entry requesting the client certificate,
+`callback` needs to be called with an entry filtered from the list.
+`event.preventDefault()` prevents from using the first certificate from
+the store.
+
## app.quit()
Try to close all windows. The `before-quit` event will first be emitted. If all