From 9c69416e322ca62930956030540a3cedf582a006 Mon Sep 17 00:00:00 2001 From: Ben Gotow Date: Tue, 17 Nov 2015 13:43:55 -0800 Subject: [PATCH 01/12] Fix sizing of Mac OS X tray icon after image change - Consolidate logic that applies view dimensions into a function - Use `NSVariableStatusItemLength` instead of trying to sync status item width - Use modern Obj-C syntax `@[], @{}` in a few places - Recompute view bounds after updating image in `setImage:` --- atom/browser/ui/tray_icon_cocoa.mm | 50 ++++++++++++++++-------------- docs/api/tray.md | 3 +- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/atom/browser/ui/tray_icon_cocoa.mm b/atom/browser/ui/tray_icon_cocoa.mm index 34ca4e9a911..0527681cd3e 100644 --- a/atom/browser/ui/tray_icon_cocoa.mm +++ b/atom/browser/ui/tray_icon_cocoa.mm @@ -40,15 +40,9 @@ const CGFloat kVerticalTitleMargin = 2; trayIcon_ = icon; isHighlightEnable_ = YES; - // Get the initial size. - NSStatusBar* statusBar = [NSStatusBar systemStatusBar]; - NSRect frame = NSMakeRect(0, 0, [self fullWidth], [statusBar thickness]); - - if ((self = [super initWithFrame:frame])) { + if ((self = [super initWithFrame: CGRectZero])) { // Setup the image view. - NSRect iconFrame = frame; - iconFrame.size.width = [self iconWidth]; - image_view_.reset([[NSImageView alloc] initWithFrame:iconFrame]); + image_view_.reset([[NSImageView alloc] initWithFrame: CGRectZero]); [image_view_ setImageScaling:NSImageScaleNone]; [image_view_ setImageAlignment:NSImageAlignCenter]; [self addSubview:image_view_]; @@ -56,17 +50,27 @@ const CGFloat kVerticalTitleMargin = 2; // Unregister image_view_ as a dragged destination, allows its parent view // (StatusItemView) handle dragging events. [image_view_ unregisterDraggedTypes]; - NSArray* types = [NSArray arrayWithObjects:NSFilenamesPboardType, nil]; - [self registerForDraggedTypes:types]; + [self registerForDraggedTypes: @[NSFilenamesPboardType]]; // Create the status item. - statusItem_.reset([[[NSStatusBar systemStatusBar] - statusItemWithLength:NSWidth(frame)] retain]); + NSStatusItem * item = [[NSStatusBar systemStatusBar] + statusItemWithLength:NSVariableStatusItemLength]; + statusItem_.reset([item retain]); [statusItem_ setView:self]; + + // Finalize setup by sizing our views + [self updateDimensions]; } return self; } +- (void)updateDimensions { + NSStatusBar * bar = [NSStatusBar systemStatusBar]; + [image_view_ setFrame: NSMakeRect(0, 0, [self iconWidth], [bar thickness])]; + [self setFrame: NSMakeRect(0, 0, [self fullWidth], [bar thickness])]; + [self setNeedsDisplay:YES]; +} + - (void)removeItem { [[NSStatusBar systemStatusBar] removeStatusItem:statusItem_]; statusItem_.reset(); @@ -81,9 +85,7 @@ const CGFloat kVerticalTitleMargin = 2; // Draw background. BOOL highlight = [self shouldHighlight]; CGFloat thickness = [[statusItem_ statusBar] thickness]; - NSRect statusItemBounds = NSMakeRect(0, 0, [statusItem_ length], thickness); - [statusItem_ drawStatusBarBackgroundInRect:statusItemBounds - withHighlight:highlight]; + [statusItem_ drawStatusBarBackgroundInRect:self.bounds withHighlight:highlight]; // Make use of NSImageView to draw the image, which can correctly draw // template image under dark menu bar. @@ -157,10 +159,10 @@ const CGFloat kVerticalTitleMargin = 2; NSColor* foregroundColor = highlight ? [NSColor whiteColor] : [NSColor colorWithRed:0.265625 green:0.25390625 blue:0.234375 alpha:1.0]; - return [NSDictionary dictionaryWithObjectsAndKeys: - font, NSFontAttributeName, - foregroundColor, NSForegroundColorAttributeName, - nil]; + return @{ + NSFontAttributeName: font, + NSForegroundColorAttributeName: foregroundColor + }; } - (NSDictionary*)titleAttributes { @@ -169,7 +171,7 @@ const CGFloat kVerticalTitleMargin = 2; - (void)setImage:(NSImage*)image { image_.reset([image copy]); - [self setNeedsDisplay:YES]; + [self updateDimensions]; } - (void)setAlternateImage:(NSImage*)image { @@ -181,12 +183,12 @@ const CGFloat kVerticalTitleMargin = 2; } - (void)setTitle:(NSString*)title { - if (title.length > 0) + if (title.length > 0) { title_.reset([title copy]); - else + } else { title_.reset(); - [statusItem_ setLength:[self fullWidth]]; - [self setNeedsDisplay:YES]; + } + [self updateDimensions]; } - (void)setMenuController:(AtomMenuController*)menu { diff --git a/docs/api/tray.md b/docs/api/tray.md index 528705acb32..7e84ad202bb 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -158,7 +158,8 @@ Sets the title displayed aside of the tray icon in the status bar. * `highlight` Boolean -Sets whether the tray icon is highlighted when it is clicked. +Sets whether the tray icon's background becomes highlighted (in blue) +when the tray icon is clicked. Defaults to true. ### `Tray.displayBalloon(options)` _Windows_ From 0dd14ad204d9951f63a0c4b24e5c511a5a82b807 Mon Sep 17 00:00:00 2001 From: Plusb Preco Date: Wed, 18 Nov 2015 09:36:14 +0900 Subject: [PATCH 02/12] 'app-command' event is only available in Windows --- docs/api/browser-window.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 3b293e99621..80b7a5f3527 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -232,7 +232,7 @@ Emitted when the window enters full screen state triggered by html api. Emitted when the window leaves full screen state triggered by html api. -### Event: 'app-command': +### Event: 'app-command' __Windows__ Emitted when an [App Command](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646275(v=vs.85).aspx) is invoked. These are typically related to keyboard media keys or browser From 0e8ab0688d00e476c0baa9b74ce5c5cfc3d37de2 Mon Sep 17 00:00:00 2001 From: Plusb Preco Date: Wed, 18 Nov 2015 09:43:28 +0900 Subject: [PATCH 03/12] Fix wrong markdown --- docs/api/browser-window.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 80b7a5f3527..e5fcfb9003a 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -232,7 +232,7 @@ Emitted when the window enters full screen state triggered by html api. Emitted when the window leaves full screen state triggered by html api. -### Event: 'app-command' __Windows__ +### Event: 'app-command' _Windows_ Emitted when an [App Command](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646275(v=vs.85).aspx) is invoked. These are typically related to keyboard media keys or browser From 1022179a1ff78c9622538ec150517ffcedffb78c Mon Sep 17 00:00:00 2001 From: Ben Gotow Date: Tue, 17 Nov 2015 17:36:37 -0800 Subject: [PATCH 04/12] Improve exception messages from remote calls Spent a while tracking down `Error processing argument -1`, caused by a missing param (`app.exit()` now takes an exit code.) Improve the rpc-server so that it prints the function name when possible, so it's much easier to identify which remote call is causing the error. --- atom/browser/lib/rpc-server.coffee | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/atom/browser/lib/rpc-server.coffee b/atom/browser/lib/rpc-server.coffee index ae4b161674b..830b966f04a 100644 --- a/atom/browser/lib/rpc-server.coffee +++ b/atom/browser/lib/rpc-server.coffee @@ -103,13 +103,25 @@ unwrapArgs = (sender, args) -> # Call a function and send reply asynchronously if it's a an asynchronous # style function and the caller didn't pass a callback. callFunction = (event, func, caller, args) -> - if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function' - args.push (ret) -> + funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous') + funcPassedCallback = args[args.length - 1] is 'function' + + try + if funcMarkedAsync and not funcPassedCallback + args.push (ret) -> + event.returnValue = valueToMeta event.sender, ret, true + func.apply caller, args + else + ret = func.apply caller, args event.returnValue = valueToMeta event.sender, ret, true - func.apply caller, args - else - ret = func.apply caller, args - event.returnValue = valueToMeta event.sender, ret, true + catch e + # Catch functions thrown further down in function invocation and wrap + # them with the function name so it's easier to trace things like + # `Error processing argument -1.` + funcName = func.name ? "anonymous" + throw new Error("Could not call remote function `#{funcName}`. + Check that the function signature is correct. + Underlying error: #{e.message}") # Send by BrowserWindow when its render view is deleted. process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (id) -> From c2eddb20f7c75473e30f45d6f495131df3a24831 Mon Sep 17 00:00:00 2001 From: "Howard.Zuo" Date: Wed, 18 Nov 2015 09:37:45 +0800 Subject: [PATCH 05/12] use loadURL since loadUrl is deprecated --- docs-translations/es/tutorial/quick-start.md | 4 ++-- docs-translations/jp/quick-start.md | 2 +- docs-translations/pt-BR/tutorial/quick-start.md | 14 +++++++------- docs-translations/zh-CN/tutorial/quick-start.md | 2 +- docs-translations/zh-TW/tutorial/quick-start.md | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs-translations/es/tutorial/quick-start.md b/docs-translations/es/tutorial/quick-start.md index 3db92177ca2..ee1127eb026 100644 --- a/docs-translations/es/tutorial/quick-start.md +++ b/docs-translations/es/tutorial/quick-start.md @@ -2,7 +2,7 @@ ## Introducción -Electron permite la creación de aplicaciones de escritorio utilizando JavaScript puro, a través de un runtime con APIs nativas. Puedes verlo como una variante de io.js, enfocado en aplicaciones de escritorio, en vez de servidores web. +Electron permite la creación de aplicaciones de escritorio utilizando JavaScript puro, a través de un runtime con APIs nativas. Puedes verlo como una variante de io.js, enfocado en aplicaciones de escritorio, en vez de servidores web. Esto no significa que Electron sea un binding de librerías GUI para JavaScript. Electron utiliza páginas web como su GUI, por lo cual puedes verlo como un navegador Chromium mínimo, @@ -94,7 +94,7 @@ app.on('ready', function() { mainWindow = new BrowserWindow({width: 800, height: 600}); // cargar el index.html de nuestra aplicación. - mainWindow.loadUrl('file://' + __dirname + '/index.html'); + mainWindow.loadURL('file://' + __dirname + '/index.html'); // Desplegar devtools. mainWindow.openDevTools(); diff --git a/docs-translations/jp/quick-start.md b/docs-translations/jp/quick-start.md index aa26a8a55ab..9a929ff84dc 100644 --- a/docs-translations/jp/quick-start.md +++ b/docs-translations/jp/quick-start.md @@ -74,7 +74,7 @@ app.on('ready', function() { mainWindow = new BrowserWindow({width: 800, height: 600}); // and load the index.html of the app. - mainWindow.loadUrl('file://' + __dirname + '/index.html'); + mainWindow.loadURL('file://' + __dirname + '/index.html'); // Open the devtools. mainWindow.openDevTools(); diff --git a/docs-translations/pt-BR/tutorial/quick-start.md b/docs-translations/pt-BR/tutorial/quick-start.md index 3ec71961a92..f9883144c82 100644 --- a/docs-translations/pt-BR/tutorial/quick-start.md +++ b/docs-translations/pt-BR/tutorial/quick-start.md @@ -5,13 +5,13 @@ um runtime com APIs ricas e nativas. Você pode ver isso como uma variação do runtime do io.js que é focado em aplicações desktop em vez de web servers. Isso não significa que o Electron é uma ligação em JavaScript para blibliotécas -de interface gráfica (GUI). Em vez disso, Electron usa páginas web como +de interface gráfica (GUI). Em vez disso, Electron usa páginas web como interface gráfica, então você pode ver isso também como um navegador Chromium mínimo, controlado por JavaScript. ### Processo Principal -No Electron, o processo que executa o script principal (main) do `package.json` +No Electron, o processo que executa o script principal (main) do `package.json` é chamado __processo principal__. O script que roda no processo principal pode mostrar uma GUI criando páginas web. @@ -38,7 +38,7 @@ correspondentes. Cada processo renderizador é isolado e toma conta de sua respectiva página web. Nas páginas web, chamar APIs nativas relacionadas à GUI não é permitido porque -gerênciar recursos de GUI em páginas web é muito perigoso e torna fácil o vazamento de +gerênciar recursos de GUI em páginas web é muito perigoso e torna fácil o vazamento de recursos. Se você quer realizar operações com GUI em páginas web, o processo renderizador da página web deve se comunicar com o processo principal para requisitar que o processo principal realize estas operações. @@ -71,7 +71,7 @@ com isso: } ``` -__Nota__: Se o campo `main` não estiver presente no `package.jso`, o Electron irá +__Nota__: Se o campo `main` não estiver presente no `package.jso`, o Electron irá tentar carregar um `index.js` O `main.js` deve criar as janelas e os manipuladores de eventos do sistema, um típico @@ -85,7 +85,7 @@ var BrowserWindow = require('browser-window'); // Módulo para criar uma janela require('crash-reporter').start(); // Mantenha uma referência global para o objeto window, se você não o fizer, -// a janela será fechada automaticamente quando o objeto JavaScript for +// a janela será fechada automaticamente quando o objeto JavaScript for // coletado pelo garbage collector. var mainWindow = null; @@ -106,7 +106,7 @@ app.on('ready', function() { mainWindow = new BrowserWindow({width: 800, height: 600}); // e carrega o index.html do app. - mainWindow.loadUrl('file://' + __dirname + '/index.html'); + mainWindow.loadURL('file://' + __dirname + '/index.html'); // Abre os DevTools. mainWindow.openDevTools(); @@ -187,6 +187,6 @@ $ ./Electron.app/Contents/MacOS/Electron your-app/ ### Executar como uma distribuição -Depois de terminar seu app, você pode criar uma distribuição seguindo o guia +Depois de terminar seu app, você pode criar uma distribuição seguindo o guia [Application Distribution](./application-distribution.md) e então executar o app empacotado. diff --git a/docs-translations/zh-CN/tutorial/quick-start.md b/docs-translations/zh-CN/tutorial/quick-start.md index 165c30142e7..906db8f4458 100644 --- a/docs-translations/zh-CN/tutorial/quick-start.md +++ b/docs-translations/zh-CN/tutorial/quick-start.md @@ -68,7 +68,7 @@ app.on('ready', function() { mainWindow = new BrowserWindow({width: 800, height: 600}); // 加载应用的 index.html - mainWindow.loadUrl('file://' + __dirname + '/index.html'); + mainWindow.loadURL('file://' + __dirname + '/index.html'); // 打开开发工具 mainWindow.openDevTools(); diff --git a/docs-translations/zh-TW/tutorial/quick-start.md b/docs-translations/zh-TW/tutorial/quick-start.md index 068138587f1..18c62c5e75c 100644 --- a/docs-translations/zh-TW/tutorial/quick-start.md +++ b/docs-translations/zh-TW/tutorial/quick-start.md @@ -85,7 +85,7 @@ app.on('ready', function() {   mainWindow = new BrowserWindow({width: 800, height: 600});   // 載入應用程式的 index.html -  mainWindow.loadUrl('file://' + __dirname + '/index.html'); +  mainWindow.loadURL('file://' + __dirname + '/index.html');   // 打開開發者工具   mainWindow.webContents.openDevTools(); @@ -174,4 +174,4 @@ $ git clone https://github.com/atom/electron-quick-start $ cd electron-quick-start # Install dependencies and run the app $ npm install && npm start -``` \ No newline at end of file +``` From 9a0dc3bfd76604b983d4cfdff227da91895b0be1 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 18 Nov 2015 10:07:03 +0800 Subject: [PATCH 06/12] Add Delegate for AtomBrowserClient --- atom/browser/api/atom_api_app.cc | 45 +++++++++++++++-------------- atom/browser/api/atom_api_app.h | 10 +++++-- atom/browser/atom_browser_client.cc | 11 ++++--- atom/browser/atom_browser_client.h | 5 ++++ atom/browser/browser.cc | 13 --------- atom/browser/browser.h | 6 ---- atom/browser/browser_observer.h | 17 ----------- 7 files changed, 41 insertions(+), 66 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index df28829c46a..b1efea5c45d 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -154,11 +154,14 @@ void PassLoginInformation(scoped_refptr login_handler, } // namespace App::App() { + static_cast(AtomBrowserClient::Get())->set_delegate(this); Browser::Get()->AddObserver(this); content::GpuDataManager::GetInstance()->AddObserver(this); } App::~App() { + static_cast(AtomBrowserClient::Get())->set_delegate( + nullptr); Browser::Get()->RemoveObserver(this); content::GpuDataManager::GetInstance()->RemoveObserver(this); } @@ -212,27 +215,6 @@ void App::OnFinishLaunching() { Emit("ready"); } -void App::OnSelectCertificate( - content::WebContents* web_contents, - net::SSLCertRequestInfo* cert_request_info, - scoped_ptr delegate) { - std::shared_ptr - 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()); -} - void App::OnLogin(LoginHandler* login_handler) { // Convert the args explicitly since they will be passed for twice. v8::Locker locker(isolate()); @@ -258,6 +240,27 @@ void App::OnLogin(LoginHandler* login_handler) { login_handler->CancelAuth(); } +void App::SelectClientCertificate( + content::WebContents* web_contents, + net::SSLCertRequestInfo* cert_request_info, + scoped_ptr delegate) { + std::shared_ptr + 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()); +} + void App::OnGpuProcessCrashed(base::TerminationStatus exit_code) { Emit("gpu-process-crashed"); } diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 683093d886c..c3793cd5426 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -8,6 +8,7 @@ #include #include "atom/browser/api/event_emitter.h" +#include "atom/browser/atom_browser_client.h" #include "atom/browser/browser_observer.h" #include "atom/common/native_mate_converters/callback.h" #include "chrome/browser/process_singleton.h" @@ -26,7 +27,8 @@ namespace atom { namespace api { -class App : public mate::EventEmitter, +class App : public AtomBrowserClient::Delegate, + public mate::EventEmitter, public BrowserObserver, public content::GpuDataManagerObserver { public: @@ -46,11 +48,13 @@ class App : public mate::EventEmitter, void OnActivate(bool has_visible_windows) override; void OnWillFinishLaunching() override; void OnFinishLaunching() override; - void OnSelectCertificate( + void OnLogin(LoginHandler* login_handler) override; + + // content::ContentBrowserClient: + void SelectClientCertificate( content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, scoped_ptr delegate) override; - void OnLogin(LoginHandler* login_handler) override; // content::GpuDataManagerObserver: void OnGpuProcessCrashed(base::TerminationStatus exit_code) override; diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 4969ce47a67..7049f4896c1 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -14,7 +14,6 @@ #include "atom/browser/atom_quota_permission_context.h" #include "atom/browser/atom_resource_dispatcher_host_delegate.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_contents_preferences.h" #include "atom/browser/window_list.h" @@ -88,7 +87,7 @@ void AtomBrowserClient::SetCustomSchemes( g_custom_schemes = JoinString(schemes, ','); } -AtomBrowserClient::AtomBrowserClient() { +AtomBrowserClient::AtomBrowserClient() : delegate_(nullptr) { } AtomBrowserClient::~AtomBrowserClient() { @@ -222,10 +221,10 @@ void AtomBrowserClient::SelectClientCertificate( return; } - if (!cert_request_info->client_certs.empty()) - Browser::Get()->ClientCertificateSelector(web_contents, - cert_request_info, - delegate.Pass()); + if (!cert_request_info->client_certs.empty() && delegate_) { + delegate_->SelectClientCertificate( + web_contents, cert_request_info, delegate.Pass()); + } } void AtomBrowserClient::ResourceDispatcherHostCreated() { diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index ee4700456cc..25849e92d4f 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -31,6 +31,9 @@ class AtomBrowserClient : public brightray::BrowserClient, AtomBrowserClient(); virtual ~AtomBrowserClient(); + using Delegate = content::ContentBrowserClient; + void set_delegate(Delegate* delegate) { delegate_ = delegate; } + // Don't force renderer process to restart for once. static void SuppressRendererProcessRestartForOnce(); // Custom schemes to be registered to standard. @@ -74,6 +77,8 @@ class AtomBrowserClient : public brightray::BrowserClient, scoped_ptr resource_dispatcher_host_delegate_; + Delegate* delegate_; + DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient); }; diff --git a/atom/browser/browser.cc b/atom/browser/browser.cc index 57741786520..c77f359760c 100644 --- a/atom/browser/browser.cc +++ b/atom/browser/browser.cc @@ -10,8 +10,6 @@ #include "atom/browser/native_window.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 { @@ -141,17 +139,6 @@ void Browser::DidFinishLaunching() { FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching()); } -void Browser::ClientCertificateSelector( - content::WebContents* web_contents, - net::SSLCertRequestInfo* cert_request_info, - scoped_ptr delegate) { - FOR_EACH_OBSERVER(BrowserObserver, - observers_, - OnSelectCertificate(web_contents, - cert_request_info, - delegate.Pass())); -} - void Browser::RequestLogin(LoginHandler* login_handler) { FOR_EACH_OBSERVER(BrowserObserver, observers_, OnLogin(login_handler)); } diff --git a/atom/browser/browser.h b/atom/browser/browser.h index e20db080b67..e46624b158d 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -126,12 +126,6 @@ class Browser : public WindowListObserver { void WillFinishLaunching(); void DidFinishLaunching(); - // Called when client certificate is required. - void ClientCertificateSelector( - content::WebContents* web_contents, - net::SSLCertRequestInfo* cert_request_info, - scoped_ptr delegate); - // Request basic auth login. void RequestLogin(LoginHandler* login_handler); diff --git a/atom/browser/browser_observer.h b/atom/browser/browser_observer.h index 7dccbfbac3c..f6d76bc13fb 100644 --- a/atom/browser/browser_observer.h +++ b/atom/browser/browser_observer.h @@ -7,17 +7,6 @@ #include -#include "base/memory/scoped_ptr.h" -#include "content/public/browser/client_certificate_delegate.h" - -namespace content { -class WebContents; -} - -namespace net { -class SSLCertRequestInfo; -} - namespace atom { class LoginHandler; @@ -53,12 +42,6 @@ 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 delegate) {} - // The browser requests HTTP login. virtual void OnLogin(LoginHandler* login_handler) {} From 341341bf28178481cfc17262395d94f7af7f5c98 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 18 Nov 2015 10:10:21 +0800 Subject: [PATCH 07/12] Rename select-certificate to select-client-certificate --- atom/browser/api/atom_api_app.cc | 2 +- atom/browser/api/lib/app.coffee | 1 + docs/api/app.md | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index b1efea5c45d..95db0c61ed7 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -247,7 +247,7 @@ void App::SelectClientCertificate( std::shared_ptr shared_delegate(delegate.release()); bool prevent_default = - Emit("select-certificate", + Emit("select-client-certificate", api::WebContents::CreateFrom(isolate(), web_contents), cert_request_info->host_and_port.ToString(), cert_request_info->client_certs, diff --git a/atom/browser/api/lib/app.coffee b/atom/browser/api/lib/app.coffee index f8d3cedd38f..44efaa24065 100644 --- a/atom/browser/api/lib/app.coffee +++ b/atom/browser/api/lib/app.coffee @@ -52,6 +52,7 @@ deprecate.event app, 'finish-launching', 'ready', -> @emit 'finish-launching' deprecate.event app, 'activate-with-no-open-windows', 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-windows' if not hasVisibleWindows +deprecate.event app, 'select-certificate', 'select-client-certificate' # Wrappers for native classes. wrapSession = (session) -> diff --git a/docs/api/app.md b/docs/api/app.md index e1a4cbf964e..4ff90f3e578 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -131,7 +131,7 @@ Returns: Emitted when a new [browserWindow](browser-window.md) is created. -### Event: 'select-certificate' +### Event: 'select-client-certificate' Returns: @@ -151,7 +151,7 @@ and `callback` needs to be called with an entry filtered from the list. Using certificate from the store. ```javascript -app.on('select-certificate', function(event, host, url, list, callback) { +app.on('select-client-certificate', function(event, webContents, url, list, callback) { event.preventDefault(); callback(list[0]); }) From e432abfb4272c9822bad5ac1ac157f9a99aa755b Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 18 Nov 2015 10:39:25 +0800 Subject: [PATCH 08/12] Add certificate-error event --- atom/browser/api/atom_api_app.cc | 53 +++++++++++++++++++--------- atom/browser/api/atom_api_app.h | 12 +++++++ atom/browser/api/atom_api_session.cc | 19 ---------- atom/browser/api/atom_api_session.h | 4 --- atom/browser/api/lib/app.coffee | 6 ++++ atom/browser/atom_browser_client.cc | 20 +++++++++++ atom/browser/atom_browser_client.h | 12 +++++++ 7 files changed, 87 insertions(+), 39 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 95db0c61ed7..73f4b392772 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -17,6 +17,7 @@ #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/net_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h" +#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/node_includes.h" #include "atom/common/options_switches.h" #include "base/command_line.h" @@ -27,6 +28,7 @@ #include "chrome/common/chrome_paths.h" #include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/gpu_data_manager.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/common/content_switches.h" #include "native_mate/dictionary.h" #include "native_mate/object_template_builder.h" @@ -216,30 +218,49 @@ void App::OnFinishLaunching() { } void App::OnLogin(LoginHandler* login_handler) { - // Convert the args explicitly since they will be passed for twice. v8::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); - auto web_contents = - WebContents::CreateFrom(isolate(), login_handler->GetWebContents()); - auto request = mate::ConvertToV8(isolate(), login_handler->request()); - auto auth_info = mate::ConvertToV8(isolate(), login_handler->auth_info()); - auto callback = mate::ConvertToV8( - isolate(), + bool prevent_default = Emit( + "login", + WebContents::CreateFrom(isolate(), login_handler->GetWebContents()), + login_handler->request(), + login_handler->auth_info(), base::Bind(&PassLoginInformation, make_scoped_refptr(login_handler))); - bool prevent_default = - Emit("login", web_contents, request, auth_info, callback); - - // Also pass it to WebContents. - if (!prevent_default) - prevent_default = - web_contents->Emit("login", request, auth_info, callback); - // Default behavior is to always cancel the auth. if (!prevent_default) login_handler->CancelAuth(); } +void App::AllowCertificateError( + int pid, + int fid, + int cert_error, + const net::SSLInfo& ssl_info, + const GURL& request_url, + content::ResourceType resource_type, + bool overridable, + bool strict_enforcement, + bool expired_previous_decision, + const base::Callback& callback, + content::CertificateRequestResultType* request) { + auto rfh = content::RenderFrameHost::FromID(pid, fid); + auto web_contents = content::WebContents::FromRenderFrameHost(rfh); + + v8::Locker locker(isolate()); + v8::HandleScope handle_scope(isolate()); + bool prevent_default = Emit("certificate-error", + WebContents::CreateFrom(isolate(), web_contents), + request_url, + cert_error, + ssl_info.cert, + callback); + + // Deny the certificate by default. + if (!prevent_default) + *request = content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY; +} + void App::SelectClientCertificate( content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, @@ -248,7 +269,7 @@ void App::SelectClientCertificate( shared_delegate(delegate.release()); bool prevent_default = Emit("select-client-certificate", - api::WebContents::CreateFrom(isolate(), web_contents), + WebContents::CreateFrom(isolate(), web_contents), cert_request_info->host_and_port.ToString(), cert_request_info->client_certs, base::Bind(&OnClientCertificateSelected, diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index c3793cd5426..ee7e0207912 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -51,6 +51,18 @@ class App : public AtomBrowserClient::Delegate, void OnLogin(LoginHandler* login_handler) override; // content::ContentBrowserClient: + void AllowCertificateError( + int render_process_id, + int render_frame_id, + int cert_error, + const net::SSLInfo& ssl_info, + const GURL& request_url, + content::ResourceType resource_type, + bool overridable, + bool strict_enforcement, + bool expired_previous_decision, + const base::Callback& callback, + content::CertificateRequestResultType* request) override; void SelectClientCertificate( content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 6527f67ab3f..3510a21668e 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -238,12 +238,6 @@ void SetProxyInIO(net::URLRequestContextGetter* getter, RunCallbackInUI(callback); } -void PassVerificationResult( - scoped_refptr request, - bool success) { - request->ContinueWithResult(success ? net::OK : net::ERR_FAILED); -} - } // namespace Session::Session(AtomBrowserContext* browser_context) @@ -262,19 +256,6 @@ Session::~Session() { Destroy(); } -void Session::RequestCertVerification( - const scoped_refptr& request) { - bool prevent_default = Emit( - "untrusted-certificate", - request->args().hostname, - request->args().cert, - base::Bind(&PassVerificationResult, request)); - - if (!prevent_default) - // Tell the request to use the result of default verifier. - request->ContinueWithResult(net::ERR_IO_PENDING); -} - void Session::OnDownloadCreated(content::DownloadManager* manager, content::DownloadItem* item) { auto web_contents = item->GetWebContents(); diff --git a/atom/browser/api/atom_api_session.h b/atom/browser/api/atom_api_session.h index db72558db47..ebcfc45223d 100644 --- a/atom/browser/api/atom_api_session.h +++ b/atom/browser/api/atom_api_session.h @@ -54,10 +54,6 @@ class Session: public mate::TrackableObject, explicit Session(AtomBrowserContext* browser_context); ~Session(); - // AtomCertVerifier::Delegate: - void RequestCertVerification( - const scoped_refptr&) override; - // content::DownloadManager::Observer: void OnDownloadCreated(content::DownloadManager* manager, content::DownloadItem* item) override; diff --git a/atom/browser/api/lib/app.coffee b/atom/browser/api/lib/app.coffee index 44efaa24065..3db4582abc7 100644 --- a/atom/browser/api/lib/app.coffee +++ b/atom/browser/api/lib/app.coffee @@ -38,6 +38,12 @@ app.getAppPath = -> # Helpers. app.resolveProxy = (url, callback) -> @defaultSession.resolveProxy url, callback +# Routes the events to webContents. +for name in ['login', 'certificate-error', 'select-client-certificate'] + do (name) -> + app.on name, (event, webContents, args...) -> + webContents.emit name, event, args... + # Deprecated. {deprecate} = electron app.getHomeDir = deprecate 'app.getHomeDir', 'app.getPath', -> diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 7049f4896c1..38fdc0e19f9 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -207,6 +207,26 @@ content::QuotaPermissionContext* return new AtomQuotaPermissionContext; } +void AtomBrowserClient::AllowCertificateError( + int render_process_id, + int render_frame_id, + int cert_error, + const net::SSLInfo& ssl_info, + const GURL& request_url, + content::ResourceType resource_type, + bool overridable, + bool strict_enforcement, + bool expired_previous_decision, + const base::Callback& callback, + content::CertificateRequestResultType* request) { + if (delegate_) { + delegate_->AllowCertificateError( + render_process_id, render_frame_id, cert_error, ssl_info, request_url, + resource_type, overridable, strict_enforcement, + expired_previous_decision, callback, request); + } +} + void AtomBrowserClient::SelectClientCertificate( content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index 25849e92d4f..75e17494593 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -57,6 +57,18 @@ class AtomBrowserClient : public brightray::BrowserClient, int child_process_id) override; void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override; content::QuotaPermissionContext* CreateQuotaPermissionContext() override; + void AllowCertificateError( + int render_process_id, + int render_frame_id, + int cert_error, + const net::SSLInfo& ssl_info, + const GURL& request_url, + content::ResourceType resource_type, + bool overridable, + bool strict_enforcement, + bool expired_previous_decision, + const base::Callback& callback, + content::CertificateRequestResultType* request) override; void SelectClientCertificate( content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, From c5bfac196914218ff98d2a45bc6287641594deea Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 18 Nov 2015 11:17:08 +0800 Subject: [PATCH 09/12] Add session.setCertificateVerifyProc --- atom/browser/api/atom_api_session.cc | 15 +++++- atom/browser/api/atom_api_session.h | 3 +- atom/browser/net/atom_cert_verifier.cc | 74 ++++++++++---------------- atom/browser/net/atom_cert_verifier.h | 61 ++++----------------- 4 files changed, 51 insertions(+), 102 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 3510a21668e..2a2c7b2fff3 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -13,6 +13,7 @@ #include "atom/browser/api/save_page_handler.h" #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" +#include "atom/browser/net/atom_cert_verifier.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h" @@ -243,7 +244,6 @@ void SetProxyInIO(net::URLRequestContextGetter* getter, Session::Session(AtomBrowserContext* browser_context) : browser_context_(browser_context) { AttachAsUserData(browser_context); - browser_context->cert_verifier()->SetDelegate(this); // Observe DownloadManger to get download notifications. content::BrowserContext::GetDownloadManager(browser_context)-> @@ -276,7 +276,6 @@ bool Session::IsDestroyed() const { } void Session::Destroy() { - browser_context_->cert_verifier()->SetDelegate(nullptr); browser_context_ = nullptr; } @@ -358,6 +357,17 @@ void Session::DisableNetworkEmulation() { base::Passed(&conditions))); } +void Session::SetCertVerifyProc(v8::Local val, mate::Arguments* args) { + AtomCertVerifier::VerifyProc proc; + if (val.IsEmpty() || + !(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &proc))) { + args->ThrowError("Must pass null or function"); + return; + } + + browser_context_->cert_verifier()->SetVerifyProc(proc); +} + v8::Local Session::Cookies(v8::Isolate* isolate) { if (cookies_.IsEmpty()) { auto handle = atom::api::Cookies::Create(isolate, browser_context()); @@ -376,6 +386,7 @@ mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder( .SetMethod("setDownloadPath", &Session::SetDownloadPath) .SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation) .SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation) + .SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc) .SetProperty("cookies", &Session::Cookies); } diff --git a/atom/browser/api/atom_api_session.h b/atom/browser/api/atom_api_session.h index ebcfc45223d..01dc0a408a8 100644 --- a/atom/browser/api/atom_api_session.h +++ b/atom/browser/api/atom_api_session.h @@ -8,7 +8,6 @@ #include #include "atom/browser/api/trackable_object.h" -#include "atom/browser/net/atom_cert_verifier.h" #include "content/public/browser/download_manager.h" #include "native_mate/handle.h" #include "net/base/completion_callback.h" @@ -35,7 +34,6 @@ class AtomBrowserContext; namespace api { class Session: public mate::TrackableObject, - public AtomCertVerifier::Delegate, public content::DownloadManager::Observer { public: using ResolveProxyCallback = base::Callback; @@ -74,6 +72,7 @@ class Session: public mate::TrackableObject, void SetDownloadPath(const base::FilePath& path); void EnableNetworkEmulation(const mate::Dictionary& options); void DisableNetworkEmulation(); + void SetCertVerifyProc(v8::Local proc, mate::Arguments* args); v8::Local Cookies(v8::Isolate* isolate); // Cached object for cookies API. diff --git a/atom/browser/net/atom_cert_verifier.cc b/atom/browser/net/atom_cert_verifier.cc index 0f94e4fe2ad..3633d805fb5 100644 --- a/atom/browser/net/atom_cert_verifier.cc +++ b/atom/browser/net/atom_cert_verifier.cc @@ -15,30 +15,31 @@ using content::BrowserThread; namespace atom { -AtomCertVerifier::CertVerifyRequest::~CertVerifyRequest() { -} +namespace { -void AtomCertVerifier::CertVerifyRequest::ContinueWithResult(int result) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - if (handled_) - return; - - handled_ = true; +void OnResult( + net::CertVerifyResult* verify_result, + const net::CompletionCallback& callback, + bool result) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(args_.callback, - result == net::ERR_IO_PENDING ? result_ : result)); + base::Bind(callback, result ? net::OK : net::ERR_FAILED)); } +} // namespace + AtomCertVerifier::AtomCertVerifier() - : delegate_(nullptr) { - default_cert_verifier_.reset(net::CertVerifier::CreateDefault()); + : default_cert_verifier_(net::CertVerifier::CreateDefault()) { } AtomCertVerifier::~AtomCertVerifier() { } +void AtomCertVerifier::SetVerifyProc(const VerifyProc& proc) { + base::AutoLock auto_lock(lock_); + verify_proc_ = proc; +} + int AtomCertVerifier::Verify( net::X509Certificate* cert, const std::string& hostname, @@ -51,45 +52,26 @@ int AtomCertVerifier::Verify( const net::BoundNetLog& net_log) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (callback.is_null() || !verify_result || hostname.empty() || !delegate_) - return net::ERR_INVALID_ARGUMENT; - - VerifyArgs args = { cert, hostname, callback }; - int result = default_cert_verifier_->Verify( - cert, hostname, ocsp_response, flags, crl_set, verify_result, - base::Bind(&AtomCertVerifier::OnDefaultVerificationResult, - base::Unretained(this), args), - out_req, net_log); - if (result != net::OK && result != net::ERR_IO_PENDING) { - // The default verifier fails immediately. - VerifyCertificateFromDelegate(args, result); - return net::ERR_IO_PENDING; + VerifyProc proc; + { + base::AutoLock auto_lock(lock_); + proc = verify_proc_; } - return result; + if (proc.is_null()) + return default_cert_verifier_->Verify( + cert, hostname, ocsp_response, flags, crl_set, verify_result, callback, + out_req, net_log); + + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(proc, hostname, make_scoped_refptr(cert), + base::Bind(OnResult, verify_result, callback))); + return net::ERR_IO_PENDING; } bool AtomCertVerifier::SupportsOCSPStapling() { return true; } -void AtomCertVerifier::VerifyCertificateFromDelegate( - const VerifyArgs& args, int result) { - CertVerifyRequest* request = new CertVerifyRequest(this, result, args); - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&Delegate::RequestCertVerification, - base::Unretained(delegate_), - make_scoped_refptr(request))); -} - -void AtomCertVerifier::OnDefaultVerificationResult( - const VerifyArgs& args, int result) { - if (result == net::OK) { - args.callback.Run(result); - return; - } - - VerifyCertificateFromDelegate(args, result); -} - } // namespace atom diff --git a/atom/browser/net/atom_cert_verifier.h b/atom/browser/net/atom_cert_verifier.h index 8736db0f872..796ae2849bd 100644 --- a/atom/browser/net/atom_cert_verifier.h +++ b/atom/browser/net/atom_cert_verifier.h @@ -8,61 +8,22 @@ #include #include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" #include "net/cert/cert_verifier.h" namespace atom { class AtomCertVerifier : public net::CertVerifier { public: - struct VerifyArgs { - scoped_refptr cert; - const std::string& hostname; - net::CompletionCallback callback; - }; - - class CertVerifyRequest - : public base::RefCountedThreadSafe { - public: - CertVerifyRequest(AtomCertVerifier* cert_verifier, - int result, - const VerifyArgs& args) - : cert_verifier_(cert_verifier), - result_(result), - args_(args), - handled_(false) { - } - - void ContinueWithResult(int result); - - const VerifyArgs& args() const { return args_; } - - private: - friend class base::RefCountedThreadSafe; - ~CertVerifyRequest(); - - AtomCertVerifier* cert_verifier_; - int result_; - VerifyArgs args_; - bool handled_; - - DISALLOW_COPY_AND_ASSIGN(CertVerifyRequest); - }; - - class Delegate { - public: - virtual ~Delegate() {} - - // Called on UI thread. - virtual void RequestCertVerification( - const scoped_refptr& request) {} - }; - AtomCertVerifier(); virtual ~AtomCertVerifier(); - void SetDelegate(Delegate* delegate) { - delegate_ = delegate; - } + using VerifyProc = + base::Callback, + const base::Callback&)>; + + void SetVerifyProc(const VerifyProc& proc); protected: // net::CertVerifier: @@ -78,12 +39,8 @@ class AtomCertVerifier : public net::CertVerifier { bool SupportsOCSPStapling() override; private: - friend class CertVerifyRequest; - - void VerifyCertificateFromDelegate(const VerifyArgs& args, int result); - void OnDefaultVerificationResult(const VerifyArgs& args, int result); - - Delegate* delegate_; + base::Lock lock_; + VerifyProc verify_proc_; scoped_ptr default_cert_verifier_; DISALLOW_COPY_AND_ASSIGN(AtomCertVerifier); From 9ca022c98a30788d2074a585128b7df8106c6c7b Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 18 Nov 2015 11:35:26 +0800 Subject: [PATCH 10/12] docs: Update the certificate APIs --- atom/browser/api/atom_api_app.cc | 2 +- docs/api/app.md | 29 ++++++++++++++++++++ docs/api/session.md | 46 +++++++++++++++----------------- docs/api/web-contents.md | 33 +++++++++++++++++++++++ 4 files changed, 84 insertions(+), 26 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 73f4b392772..28c3b4c1598 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -252,7 +252,7 @@ void App::AllowCertificateError( bool prevent_default = Emit("certificate-error", WebContents::CreateFrom(isolate(), web_contents), request_url, - cert_error, + net::ErrorToString(cert_error), ssl_info.cert, callback); diff --git a/docs/api/app.md b/docs/api/app.md index 4ff90f3e578..d7850c4cb92 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -131,6 +131,35 @@ Returns: Emitted when a new [browserWindow](browser-window.md) is created. +### Event: 'certificate-error' + +Returns: + +* `event` Event +* `webContents` [WebContents](web-contents.md) +* `url` URL +* `error` String - The error code +* `certificate` Object + * `data` Buffer - PEM encoded data + * `issuerName` String +* `callback` Function + +Emitted when failed to verify the `certificate` for `url`, to trust the +certificate you should prevent the default behavior with +`event.preventDefault()` and call `callback(true)`. + +```javascript +session.on('certificate-error', function(event, webContents, url, error, certificate, callback) { + if (url == "https://github.com") { + // Verification logic. + event.preventDefault(); + callback(true); + } else { + callback(false); + } +}); +``` + ### Event: 'select-client-certificate' Returns: diff --git a/docs/api/session.md b/docs/api/session.md index e385e222d52..450be7b08e1 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -34,31 +34,6 @@ session.on('will-download', function(event, item, webContents) { }); ``` -### Event: 'untrusted-certificate' - -* `event` Event -* `hostname` String -* `certificate` Object - * `data` Buffer - PEM encoded data - * `issuerName` String -* `callback` Function - -Emitted when failed to verify the `certificate` for `hostname`, to trust the -certificate you should prevent the default behavior with -`event.preventDefault()` and call `callback(true)`. - -```js -session.on('verify-certificate', function(event, hostname, certificate, callback) { - if (hostname == "github.com") { - // Verification logic. - event.preventDefault(); - callback(true); - } else { - callback(false); - } -}); -``` - ## Methods The `session` object has the following methods: @@ -245,3 +220,24 @@ window.webContents.session.enableNetworkEmulation({offline: true}); Disables any network emulation already active for the `session`. Resets to the original network configuration. + +### `session.setCertificateVerifyProc(proc)` + +* `proc` Function + +Sets the certificate verify proc for `session`, the `proc` will be called with +`proc(hostname, certificate, callback)` whenever a server certificate +verification is requested. Calling `callback(true)` accepts the certificate, +calling `callback(false)` rejects it. + +Calling `setCertificateVerifyProc(null)` will revert back to default certificate +verify proc. + +```javascript +myWindow.webContents.session.setCertificateVerifyProc(function(hostname, cert, callback) { + if (hostname == 'github.com') + callback(true); + else + callback(false); +}); +``` diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 0988d25276f..be22d947c75 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -167,6 +167,39 @@ Emitted when DevTools is closed. Emitted when DevTools is focused / opened. +### Event: 'certificate-error' + +Returns: + +* `event` Event +* `url` URL +* `error` String - The error code +* `certificate` Object + * `data` Buffer - PEM encoded data + * `issuerName` String +* `callback` Function + +Emitted when failed to verify the `certificate` for `url`. + +The usage is the same with [the `certificate-error` event of +`app`](app.md#event-certificate-error). + +### Event: 'select-client-certificate' + +Returns: + +* `event` Event +* `url` URL +* `certificateList` [Objects] + * `data` Buffer - PEM encoded data + * `issuerName` String - Issuer's Common Name +* `callback` Function + +Emitted when a client certificate is requested. + +The usage is the same with [the `select-client-certificate` event of +`app`](app.md#event-select-client-certificate). + ### Event: 'login' Returns: From 47d7f2c0503231054a80a5c2a3769cf01ddcfbbb Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 18 Nov 2015 11:45:15 +0800 Subject: [PATCH 11/12] Fix cpplint warning --- atom/browser/api/atom_api_session.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index 2a2c7b2fff3..27e1521f3d3 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -357,10 +357,10 @@ void Session::DisableNetworkEmulation() { base::Passed(&conditions))); } -void Session::SetCertVerifyProc(v8::Local val, mate::Arguments* args) { +void Session::SetCertVerifyProc(v8::Local val, + mate::Arguments* args) { AtomCertVerifier::VerifyProc proc; - if (val.IsEmpty() || - !(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &proc))) { + if (!(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &proc))) { args->ThrowError("Must pass null or function"); return; } From bcdd0952f8decce11bf30723422142cf624e3440 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 18 Nov 2015 17:56:50 +0800 Subject: [PATCH 12/12] docs: Fix typo --- docs/api/protocol.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/protocol.md b/docs/api/protocol.md index 0f854a2bb2f..5f34165fa84 100644 --- a/docs/api/protocol.md +++ b/docs/api/protocol.md @@ -103,7 +103,7 @@ Registers a protocol of `scheme` that will send a `String` as a response. The Registers a protocol of `scheme` that will send an HTTP request as a response. The `callback` should be called with an object that has the `url`, `method`, -`referer`, and `session` properties. +`referrer`, and `session` properties. By default the HTTP request will reuse the current session. If you want the request to have a different session you should set `session` to `null`.