Merge branch 'support-chromium-sandbox' of https://github.com/tarruda/electron into tarruda-support-chromium-sandbox

This commit is contained in:
Cheng Zhao 2016-09-27 20:02:23 +08:00
commit 458c4dd129
35 changed files with 1055 additions and 100 deletions

View file

@ -258,17 +258,25 @@ void OnCapturePageDone(base::Callback<void(const gfx::Image&)> callback,
} // namespace
WebContents::WebContents(v8::Isolate* isolate,
content::WebContents* web_contents)
content::WebContents* web_contents,
Type type)
: content::WebContentsObserver(web_contents),
embedder_(nullptr),
type_(REMOTE),
type_(type),
request_id_(0),
background_throttling_(true),
enable_devtools_(true) {
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
Init(isolate);
AttachAsUserData(web_contents);
if (type == REMOTE) {
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
Init(isolate);
AttachAsUserData(web_contents);
} else {
const mate::Dictionary options = mate::Dictionary::CreateEmpty(isolate);
auto session = Session::CreateFrom(isolate, GetBrowserContext());
session_.Reset(isolate, session.ToV8());
InitWithSessionAndOptions(isolate, web_contents, session, options);
}
}
WebContents::WebContents(v8::Isolate* isolate,
@ -336,6 +344,13 @@ WebContents::WebContents(v8::Isolate* isolate,
web_contents = content::WebContents::Create(params);
}
InitWithSessionAndOptions(isolate, web_contents, session, options);
}
void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
content::WebContents *web_contents,
mate::Handle<api::Session> session,
const mate::Dictionary& options) {
Observe(web_contents);
InitWithWebContents(web_contents, session->browser_context());
@ -408,6 +423,31 @@ void WebContents::OnCreateWindow(const GURL& target_url,
Emit("new-window", target_url, frame_name, disposition);
}
void WebContents::WebContentsCreated(content::WebContents* source_contents,
int opener_render_frame_id,
const std::string& frame_name,
const GURL& target_url,
content::WebContents* new_contents) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto api_web_contents = CreateFrom(isolate(), new_contents, BROWSER_WINDOW);
Emit("-web-contents-created", api_web_contents, target_url, frame_name);
}
void WebContents::AddNewContents(content::WebContents* source,
content::WebContents* new_contents,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture,
bool* was_blocked) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto api_web_contents = CreateFrom(isolate(), new_contents);
Emit("-add-new-contents", api_web_contents, disposition, user_gesture,
initial_rect.x(), initial_rect.y(), initial_rect.width(),
initial_rect.height());
}
content::WebContents* WebContents::OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) {
@ -801,7 +841,14 @@ void WebContents::NavigationEntryCommitted(
details.is_in_page, details.did_replace_entry);
}
int WebContents::GetID() const {
int64_t WebContents::GetID() const {
int64_t process_id = web_contents()->GetRenderProcessHost()->GetID();
int64_t routing_id = web_contents()->GetRoutingID();
int64_t rv = (process_id << 32) + routing_id;
return rv;
}
int WebContents::GetProcessID() const {
return web_contents()->GetRenderProcessHost()->GetID();
}
@ -1496,6 +1543,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
.MakeDestroyable()
.SetMethod("getId", &WebContents::GetID)
.SetMethod("getProcessId", &WebContents::GetProcessID)
.SetMethod("equal", &WebContents::Equal)
.SetMethod("_loadURL", &WebContents::LoadURL)
.SetMethod("downloadURL", &WebContents::DownloadURL)
@ -1605,7 +1653,15 @@ mate::Handle<WebContents> WebContents::CreateFrom(
return mate::CreateHandle(isolate, static_cast<WebContents*>(existing));
// Otherwise create a new WebContents wrapper object.
return mate::CreateHandle(isolate, new WebContents(isolate, web_contents));
return mate::CreateHandle(isolate, new WebContents(isolate, web_contents,
REMOTE));
}
mate::Handle<WebContents> WebContents::CreateFrom(
v8::Isolate* isolate, content::WebContents* web_contents, Type type) {
// Otherwise create a new WebContents wrapper object.
return mate::CreateHandle(isolate, new WebContents(isolate, web_contents,
type));
}
// static

View file

@ -58,6 +58,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
// Create from an existing WebContents.
static mate::Handle<WebContents> CreateFrom(
v8::Isolate* isolate, content::WebContents* web_contents);
static mate::Handle<WebContents> CreateFrom(
v8::Isolate* isolate, content::WebContents* web_contents, Type type);
// Create a new WebContents.
static mate::Handle<WebContents> Create(
@ -66,7 +68,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype);
int GetID() const;
int64_t GetID() const;
int GetProcessID() const;
Type GetType() const;
bool Equal(const WebContents* web_contents) const;
void LoadURL(const GURL& url, const mate::Dictionary& options);
@ -191,16 +194,34 @@ class WebContents : public mate::TrackableObject<WebContents>,
v8::Local<v8::Value> Debugger(v8::Isolate* isolate);
protected:
WebContents(v8::Isolate* isolate, content::WebContents* web_contents);
WebContents(v8::Isolate* isolate,
content::WebContents* web_contents,
Type type);
WebContents(v8::Isolate* isolate, const mate::Dictionary& options);
~WebContents();
void InitWithSessionAndOptions(v8::Isolate* isolate,
content::WebContents *web_contents,
mate::Handle<class Session> session,
const mate::Dictionary& options);
// content::WebContentsDelegate:
bool AddMessageToConsole(content::WebContents* source,
int32_t level,
const base::string16& message,
int32_t line_no,
const base::string16& source_id) override;
void WebContentsCreated(content::WebContents* source_contents,
int opener_render_frame_id,
const std::string& frame_name,
const GURL& target_url,
content::WebContents* new_contents) override;
void AddNewContents(content::WebContents* source,
content::WebContents* new_contents,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture,
bool* was_blocked) override;
content::WebContents* OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) override;

View file

@ -72,20 +72,33 @@ v8::Local<v8::Value> ToBuffer(v8::Isolate* isolate, void* val, int size) {
Window::Window(v8::Isolate* isolate, v8::Local<v8::Object> wrapper,
const mate::Dictionary& options) {
// Use options.webPreferences to create WebContents.
mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate);
options.Get(options::kWebPreferences, &web_preferences);
mate::Handle<class WebContents> web_contents;
// If no WebContents was passed to the constructor, create it from options.
if (!options.Get("webContents", &web_contents)) {
// Use options.webPreferences to create WebContents.
mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate);
options.Get(options::kWebPreferences, &web_preferences);
// Copy the backgroundColor to webContents.
v8::Local<v8::Value> value;
if (options.Get(options::kBackgroundColor, &value))
web_preferences.Set(options::kBackgroundColor, value);
// Copy the backgroundColor to webContents.
v8::Local<v8::Value> value;
if (options.Get(options::kBackgroundColor, &value))
web_preferences.Set(options::kBackgroundColor, value);
v8::Local<v8::Value> transparent;
if (options.Get("transparent", &transparent))
web_preferences.Set("transparent", transparent);
// Creates the WebContents used by BrowserWindow.
auto web_contents = WebContents::Create(isolate, web_preferences);
v8::Local<v8::Value> transparent;
if (options.Get("transparent", &transparent))
web_preferences.Set("transparent", transparent);
// Creates the WebContents used by BrowserWindow.
web_contents = WebContents::Create(isolate, web_preferences);
}
Init(isolate, wrapper, options, web_contents);
}
void Window::Init(v8::Isolate* isolate,
v8::Local<v8::Object> wrapper,
const mate::Dictionary& options,
mate::Handle<class WebContents> web_contents) {
web_contents_.Reset(isolate, web_contents.ToV8());
api_web_contents_ = web_contents.get();

View file

@ -89,6 +89,10 @@ class Window : public mate::TrackableObject<Window>,
#endif
private:
void Init(v8::Isolate* isolate,
v8::Local<v8::Object> wrapper,
const mate::Dictionary& options,
mate::Handle<class WebContents> web_contents);
// APIs for NativeWindow.
void Close();
void Focus();

View file

@ -99,6 +99,44 @@ content::WebContents* AtomBrowserClient::GetWebContentsFromProcessID(
return WebContentsPreferences::GetWebContentsFromProcessID(process_id);
}
bool AtomBrowserClient::ShouldCreateNewSiteInstance(
content::BrowserContext* browser_context,
content::SiteInstance* current_instance,
const GURL& url) {
if (url.SchemeIs(url::kJavaScriptScheme))
// "javacript:" scheme should always use same SiteInstance
return false;
if (!IsRendererSandboxed(current_instance->GetProcess()->GetID()))
// non-sandboxed renderers should always create a new SiteInstance
return true;
// Create new a SiteInstance if navigating to a different site.
auto src_url = current_instance->GetSiteURL();
return
!content::SiteInstance::IsSameWebSite(browser_context, src_url, url) &&
// `IsSameWebSite` doesn't seem to work for some URIs such as `file:`,
// handle these scenarios by comparing only the site as defined by
// `GetSiteForURL`.
content::SiteInstance::GetSiteForURL(browser_context, url) != src_url;
}
void AtomBrowserClient::AddSandboxedRendererId(int process_id) {
base::AutoLock auto_lock(sandboxed_renderers_lock_);
sandboxed_renderers_.insert(process_id);
}
void AtomBrowserClient::RemoveSandboxedRendererId(int process_id) {
base::AutoLock auto_lock(sandboxed_renderers_lock_);
sandboxed_renderers_.erase(process_id);
}
bool AtomBrowserClient::IsRendererSandboxed(int process_id) {
base::AutoLock auto_lock(sandboxed_renderers_lock_);
return sandboxed_renderers_.count(process_id);
}
void AtomBrowserClient::RenderProcessWillLaunch(
content::RenderProcessHost* host) {
int process_id = host->GetID();
@ -106,6 +144,13 @@ void AtomBrowserClient::RenderProcessWillLaunch(
host->AddFilter(new TtsMessageFilter(process_id, host->GetBrowserContext()));
host->AddFilter(
new WidevineCdmMessageFilter(process_id, host->GetBrowserContext()));
content::WebContents* web_contents = GetWebContentsFromProcessID(process_id);
if (WebContentsPreferences::IsSandboxed(web_contents)) {
AddSandboxedRendererId(host->GetID());
// ensure the sandboxed renderer id is removed later
host->AddObserver(this);
}
}
content::SpeechRecognitionManagerDelegate*
@ -155,8 +200,7 @@ void AtomBrowserClient::OverrideSiteInstanceForNavigation(
return;
}
// Restart renderer process for all navigations except "javacript:" scheme.
if (url.SchemeIs(url::kJavaScriptScheme))
if (!ShouldCreateNewSiteInstance(browser_context, current_instance, url))
return;
scoped_refptr<content::SiteInstance> site_instance =
@ -188,6 +232,7 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
// Copy following switches to child process.
static const char* const kCommonSwitchNames[] = {
switches::kStandardSchemes,
switches::kEnableSandbox
};
command_line->CopySwitchesFrom(
*base::CommandLine::ForCurrentProcess(),
@ -281,6 +326,11 @@ bool AtomBrowserClient::CanCreateWindow(
bool* no_javascript_access) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (IsRendererSandboxed(render_process_id)) {
*no_javascript_access = false;
return true;
}
if (delegate_) {
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&api::App::OnCreateWindow,
@ -338,6 +388,7 @@ void AtomBrowserClient::RenderProcessHostDestroyed(
break;
}
}
RemoveSandboxedRendererId(process_id);
}
} // namespace atom

View file

@ -6,6 +6,7 @@
#define ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_
#include <map>
#include <set>
#include <string>
#include <vector>
@ -108,8 +109,19 @@ class AtomBrowserClient : public brightray::BrowserClient,
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
private:
bool ShouldCreateNewSiteInstance(content::BrowserContext* browser_context,
content::SiteInstance* current_instance,
const GURL& dest_url);
// Add/remove a process id to `sandboxed_renderers_`.
void AddSandboxedRendererId(int process_id);
void RemoveSandboxedRendererId(int process_id);
bool IsRendererSandboxed(int process_id);
// pending_render_process => current_render_process.
std::map<int, int> pending_processes_;
// Set that contains the process ids of all sandboxed renderers
std::set<int> sandboxed_renderers_;
base::Lock sandboxed_renderers_lock_;
std::unique_ptr<AtomResourceDispatcherHostDelegate>
resource_dispatcher_host_delegate_;

View file

@ -391,6 +391,10 @@ void NativeWindow::RequestToClosePage() {
if (window_unresposive_closure_.IsCancelled())
ScheduleUnresponsiveEvent(5000);
if (!web_contents())
// Already closed by renderer
return;
if (web_contents()->NeedToFireBeforeUnload())
web_contents()->DispatchBeforeUnload();
else

View file

@ -97,6 +97,12 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches(
command_line->AppendSwitchASCII(switches::kNodeIntegration,
node_integration ? "true" : "false");
// If the `sandbox` option was passed to the BrowserWindow's webPreferences,
// pass `--enable-sandbox` to the renderer so it won't have any node.js
// integration.
if (IsSandboxed(web_contents))
command_line->AppendSwitch(switches::kEnableSandbox);
// The preload script.
base::FilePath::StringType preload;
if (web_preferences.GetString(options::kPreloadScript, &preload)) {
@ -194,6 +200,21 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches(
command_line->AppendSwitch(cc::switches::kEnableBeginFrameScheduling);
}
bool WebContentsPreferences::IsSandboxed(content::WebContents* web_contents) {
WebContentsPreferences* self;
if (!web_contents)
return false;
self = FromWebContents(web_contents);
if (!self)
return false;
base::DictionaryValue& web_preferences = self->web_preferences_;
bool sandboxed = false;
web_preferences.GetBoolean("sandbox", &sandboxed);
return sandboxed;
}
// static
void WebContentsPreferences::OverrideWebkitPrefs(
content::WebContents* web_contents, content::WebPreferences* prefs) {

View file

@ -36,6 +36,8 @@ class WebContentsPreferences
static void AppendExtraCommandLineSwitches(
content::WebContents* web_contents, base::CommandLine* command_line);
static bool IsSandboxed(content::WebContents* web_contents);
// Modify the WebPreferences according to |web_contents|'s preferences.
static void OverrideWebkitPrefs(
content::WebContents* web_contents, content::WebPreferences* prefs);